aGrUM 3.0.0
a C++ library for (probabilistic) graphical models
gum::Separation Class Reference

Consolidated d-separation utilities (DAG-centric). More...

#include <separation.h>

Static Public Member Functions

static bool isDSeparated (const DAG &dag, const NodeSet &X, const NodeSet &Y, const NodeSet &Z)
 Test ( X \perp!!!\perp Y \mid Z ) (general d-separation).
static bool isBackdoorSeparated (const DAG &dag, const NodeSet &X, const NodeSet &Y, const NodeSet &Z)
 Backdoor-style restriction: only paths whose first edge points into X.
static bool isForwardSeparated (const DAG &dag, const NodeSet &X, const NodeSet &Y, const NodeSet &Z)
 Forward-style restriction: only paths whose first edge leaves X.
static DAG reduceForDSeparation (const DAG &dag, const NodeSet &X, const NodeSet &Y, const NodeSet &Z)
 Barren-node pruning relative to the interest set (X \cup Y \cup Z).
static NodeSet findBarrenNodes (const DAG &dag, const NodeSet &evidenceZ, const NodeSet &targetsXY)
 Compute barren nodes given evidence and targets.
static bool isAncestorOf (const DAG &dag, NodeId x, NodeId y)
 Is x an ancestor of y?
static bool isDescendantOf (const DAG &dag, NodeId x, NodeId y)
 Is x a descendant of y?

Static Private Member Functions

static bool anyUndirectedConnection (const UndiGraph &ug, const NodeSet &A, const NodeSet &B)
 Check if any node in A is undirected-connected to any node in B.

Detailed Description

Consolidated d-separation utilities (DAG-centric).

High-level helpers to test (conditional) independence in directed acyclic graphs (DAGs) using the d-separation criterion. Wherever possible, this class delegates to aGrUM-provided primitives and mirrors pyAgrum semantics.

C++ ↔ pyAgrum correspondence

Definition at line 75 of file separation.h.

Member Function Documentation

◆ anyUndirectedConnection()

bool gum::Separation::anyUndirectedConnection ( const UndiGraph & ug,
const NodeSet & A,
const NodeSet & B )
staticprivate

Check if any node in A is undirected-connected to any node in B.

Pyagrum counterpart: _is_path_x_y.

Parameters
ugAn undirected graph (usually a moralized ancestral graph).
AFirst node set.
BSecond node set.
Returns
true iff there exists an undirected path between some a ∈ A and some b ∈ B in ug.

Definition at line 217 of file separation.cpp.

217 {
218 return graph::areConnected(ug, A, B);
219 }
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.

References gum::graph::areConnected().

Referenced by isForwardSeparated().

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

◆ findBarrenNodes()

NodeSet gum::Separation::findBarrenNodes ( const DAG & dag,
const NodeSet & evidenceZ,
const NodeSet & targetsXY )
static

Compute barren nodes given evidence and targets.

Pyagrum counterpart: _barren_nodes.

Thin wrapper over BarrenNodesFinder::barrenNodes().

Parameters
dagThe causal DAG.
evidenceZEvidence/conditioning set Z.
targetsXYUnion of target nodes (typically (X \cup Y)).
Returns
Set of barren nodes that can be pruned without affecting d-sep.

Implementation note: Conservative stand-in: nodes outside Anc(X∪Y∪Z) are "barren" for our purpose. If BarrenNodesFinder::barrenNodes() is available, you can implement this as a thin wrapper around it.

Definition at line 182 of file separation.cpp.

184 {
185 gum::BarrenNodesFinder finder(&dag);
186 finder.setTargets(&targetsXY);
187 finder.setEvidence(&evidenceZ);
188 return finder.barrenNodes();
189 }

References gum::BarrenNodesFinder::barrenNodes(), gum::BarrenNodesFinder::setEvidence(), and gum::BarrenNodesFinder::setTargets().

Here is the call graph for this function:

◆ isAncestorOf()

bool gum::Separation::isAncestorOf ( const DAG & dag,
NodeId x,
NodeId y )
static

Is x an ancestor of y?

Pyagrum counterpart: _is_ascendant.

Parameters
dagThe causal DAG.
xCandidate ancestor.
yCandidate descendant.
Returns
true iff (x \in \mathrm{Anc}(y)).

Definition at line 198 of file separation.cpp.

198 {
199 return dag.ancestors(y).contains(x);
200 }

References gum::DiGraph::ancestors(), and gum::Set< Key >::contains().

Here is the call graph for this function:

◆ isBackdoorSeparated()

bool gum::Separation::isBackdoorSeparated ( const DAG & dag,
const NodeSet & X,
const NodeSet & Y,
const NodeSet & Z )
static

Backdoor-style restriction: only paths whose first edge points into X.

Pyagrum counterpart: isDSep_parents / _isDSep_tech2_parents.

Semantics: tests whether Z blocks all paths from Y to X that enter X via an incoming edge (the “backdoor graph” (G_{\underline{X}})).

Implementation:

  1. Copy dag to g.
  2. For each (x \in X), erase every outgoing arc (x \to c) in g.
  3. Return g.dSeparation(X, Y, Z).
Parameters
dagThe causal DAG.
XSet of “treatment” nodes (incoming-edge focus).
YSet of outcome nodes.
ZConditioning set.
Returns
true iff Z d-separates X and Y in the backdoor graph (G_{\underline{X}}).

Definition at line 91 of file separation.cpp.

94 {
95 // Build G_{\underline X}: remove all outgoing arcs from X
96 DAG g = dag;
97
98 for (auto x: X) {
99 // collect children first, then erase (avoid iterator invalidation)
100 std::vector< NodeId > ch;
101 ch.reserve(g.children(x).size());
102 for (auto c: g.children(x))
103 ch.push_back(c);
104
105 for (auto c: ch) {
106 if (g.existsArc(x, c)) g.eraseArc(gum::Arc(x, c));
107 }
108 }
109
110 // Now test standard d-separation in G_{\underline X}
111 return g.dSeparation(X, Y, Z);
112 }

References gum::ArcGraphPart::children(), gum::DAG::dSeparation(), gum::ArcGraphPart::eraseArc(), gum::ArcGraphPart::existsArc(), and gum::Set< Key >::size().

Referenced by gum::CausalImpact< GUM_ELEMENT >::_namesToIds_(), gum::DoorCriteria::enumerateBackdoorSets(), gum::DoorCriteria::enumerateFrontdoorSets(), gum::DoorCriteria::hasBackdoorPath(), gum::DoorCriteria::satisfiesBackdoorCriterion(), and gum::DoorCriteria::satisfiesFrontdoorCriterion().

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

◆ isDescendantOf()

bool gum::Separation::isDescendantOf ( const DAG & dag,
NodeId x,
NodeId y )
static

Is x a descendant of y?

Pyagrum counterpart: _is_descendant.

Parameters
dagThe causal DAG.
xCandidate descendant.
yCandidate ancestor.
Returns
true iff (x \in \mathrm{Desc}(y)).

Definition at line 205 of file separation.cpp.

205 {
206 return dag.descendants(y).contains(x);
207 }

References gum::Set< Key >::contains(), and gum::DiGraph::descendants().

Here is the call graph for this function:

◆ isDSeparated()

bool gum::Separation::isDSeparated ( const DAG & dag,
const NodeSet & X,
const NodeSet & Y,
const NodeSet & Z )
static

Test ( X \perp!!!\perp Y \mid Z ) (general d-separation).

Pyagrum counterpart: isDSep (delegates to isDSep_tech2).

Delegates to DAG::dSeparation, which:

  1. Builds the moralized ancestral graph of (X \cup Y \cup Z).
  2. Removes nodes in (Z).
  3. Checks undirected connectivity between (X) and (Y).
Parameters
dagThe causal DAG.
XSet of source nodes.
YSet of target nodes.
ZConditioning set.
Returns
true iff (X) is d-separated from (Y) given (Z) in dag.

Definition at line 80 of file separation.cpp.

83 {
84 // delegate directly to aGrUM's built-in d-separation
85 return dag.dSeparation(X, Y, Z);
86 }

References gum::DAG::dSeparation().

Referenced by gum::DoCalculus< GUM_SCALAR >::doCalculusWithObservation().

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

◆ isForwardSeparated()

bool gum::Separation::isForwardSeparated ( const DAG & dag,
const NodeSet & X,
const NodeSet & Y,
const NodeSet & Z )
static

Forward-style restriction: only paths whose first edge leaves X.

Pyagrum counterpart: _isDSep_tech2_children.

Semantics: tests whether Z blocks all paths starting from X via an outgoing edge (children-first restriction used in frontdoor checks).

Outline:

  1. Let interest = Anc(Y ∪ Z). Build the moralized ancestral graph: UndiGraph ug = dag.moralizedAncestralGraph(interest).
  2. Ensure each (x \in X) exists in ug (add isolated node if missing), but do not add (x)–parent links.
  3. For each (x \in X), add an undirected edge (x)—(c) for every child (c) of (x) present in ug.
  4. Remove all nodes in (Z) from ug.
  5. Return true iff there is no undirected path between any node in X and any node in Y.
Parameters
dagThe causal DAG.
XSet of start nodes (outgoing-edge focus).
YSet of target nodes.
ZConditioning set.
Returns
true iff Z blocks all forward/children paths from X to Y.

Definition at line 117 of file separation.cpp.

120 {
121 // 1) Moralize only on Anc(Y ∪ Z)
122 NodeSet interest = Y;
123 for (auto z: Z)
124 interest.insert(z);
125 UndiGraph ug = dag.moralizedAncestralGraph(interest);
126
127 // Ensure nodes in X exist in ug (without adding X—parent edges)
128 for (auto x: X)
129 if (!ug.existsNode(x)) ug.addNodeWithId(x);
130
131 // 2) Add edges X—c for children c of X that are already in ug
132 for (auto x: X) {
133 for (auto c: dag.children(x)) {
134 if (ug.existsNode(c) && !ug.existsEdge(x, c)) ug.addEdge(x, c);
135 }
136 }
137
138 // 3) Remove conditioning nodes Z
139 removeConditioningNodes(ug, Z);
140
141 // 4) Return true iff there is no undirected path between X and Y
142 return !anyUndirectedConnection(ug, X, Y);
143 }
static bool anyUndirectedConnection(const UndiGraph &ug, const NodeSet &A, const NodeSet &B)
Check if any node in A is undirected-connected to any node in B.
void insert(const Key &k)
Inserts a new element into the set.
Definition set_tpl.h:510
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...

References gum::UndiGraph::addEdge(), gum::NodeGraphPart::addNodeWithId(), anyUndirectedConnection(), gum::ArcGraphPart::children(), gum::EdgeGraphPart::existsEdge(), gum::NodeGraphPart::existsNode(), gum::Set< Key >::insert(), and gum::DAG::moralizedAncestralGraph().

Here is the call graph for this function:

◆ reduceForDSeparation()

DAG gum::Separation::reduceForDSeparation ( const DAG & dag,
const NodeSet & X,
const NodeSet & Y,
const NodeSet & Z )
static

Barren-node pruning relative to the interest set (X \cup Y \cup Z).

Pyagrum counterpart: dSep_reduce (uses _barren_nodes).

Uses BarrenNodesFinder with evidence = Z and targets = X ∪ Y to compute barren nodes, then removes them from a copy of dag.

Parameters
dagThe causal DAG to prune.
XSource nodes of interest.
YTarget nodes of interest.
ZEvidence/conditioning set.
Returns
A reduced DAG with barren nodes removed (safe for d-sep queries).

Definition at line 153 of file separation.cpp.

156 {
157 // Targets = X ∪ Y
158 const NodeSet targets{X + Y};
159
160 // Configure finder
161 gum::BarrenNodesFinder finder(&dag);
162 finder.setTargets(&targets); // nodes we care about reaching
163 finder.setEvidence(&Z); // observed nodes
164
165 // Compute barren nodes and remove them from a copy
166 const NodeSet barren = finder.barrenNodes();
167 DAG reduced{dag};
168 for (auto n: barren)
169 if (reduced.existsNode(n)) reduced.eraseNode(n);
170
171 return reduced;
172 }

References gum::BarrenNodesFinder::barrenNodes(), gum::DiGraph::eraseNode(), gum::NodeGraphPart::existsNode(), gum::BarrenNodesFinder::setEvidence(), and gum::BarrenNodesFinder::setTargets().

Referenced by gum::DoorCriteria::enumerateBackdoorSets(), gum::DoorCriteria::enumerateFrontdoorSets(), and gum::DoorCriteria::satisfiesFrontdoorCriterion().

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

The documentation for this class was generated from the following files: