62 std::vector< NodeId > _sortedVec(
const NodeSet& s) {
63 std::vector< NodeId > v;
77 NodeId minDiff = std::numeric_limits< NodeId >::max();
81 if (!b.exists(n) && n < minDiff) {
86 if (!a.exists(n) && n < minDiff) {
91 if (minDiff == std::numeric_limits< NodeId >::max())
return false;
96 if (n > minDiff)
return true;
101 if (n > minDiff)
return false;
121 for (
auto dx: descX) {
137 if (Z.
empty())
return false;
170 std::size_t max_cardinality,
193 out.push_back(Zempty);
194 if (only_minimal || stopAtFirst)
return out;
202 for (
auto n: G.
nodes()) {
203 if (n == X || n == Y)
continue;
204 if (excluded_nodes.
contains(n))
continue;
208 if (possible.
empty())
return out;
210 auto cand = _sortedVec(possible);
211 const std::size_t N = cand.size();
212 const std::size_t Kmax = (max_cardinality == 0) ? N : std::min(max_cardinality, N);
216 const bool prune_supersets = only_minimal;
224 for (std::size_t k = 1; k <= Kmax; ++k) {
225 std::vector< bool > pick(N,
false);
226 std::fill_n(pick.begin(), k,
true);
229 for (std::size_t i = 0; i < N; ++i)
230 if (pick[i]) Z.
insert(cand[i]);
232 if (prune_supersets) {
234 for (
const auto& s: chosen) {
246 if (!worth)
continue;
256 if (stopAtFirst)
return out;
259 }
while (std::prev_permutation(pick.begin(), pick.end()));
263 std::sort(out.begin(), out.end(), _lexLess);
264 out.erase(std::unique(out.begin(),
267 return _sortedVec(a) == _sortedVec(b);
282 std::size_t max_cardinality,
289 if (p == X) {
return out; }
294 bool noDiPath = !possibleOpt.has_value();
297 if (possibleOpt.has_value()) { possible = *possibleOpt; }
303 std::vector< NodeId > st;
306 while (!st.empty()) {
321 if (!cc.
contains(Y)) {
return out; }
336 for (
auto n: excluded_nodes) {
353 for (
auto z: possible) {
358 for (
auto z: impossible) {
362 if (possible.
empty()) {
return out; }
364 auto cand = _sortedVec(possible);
372 if (stopAtFirst) {
return out; }
375 const std::size_t N = cand.size();
376 const std::size_t Kmax = (max_cardinality == 0) ? N : std::min(max_cardinality, N);
377 for (std::size_t k = 1; k <= Kmax; ++k) {
378 std::vector< bool > pick(N,
false);
379 std::fill_n(pick.begin(), k,
true);
382 for (std::size_t i = 0; i < N; ++i) {
383 if (pick[i]) { Z.
insert(cand[i]); }
389 if (stopAtFirst) {
return out; }
392 }
while (std::prev_permutation(pick.begin(), pick.end()));
396 std::sort(out.begin(), out.end(), _lexLess);
397 out.erase(std::unique(out.begin(),
400 return _sortedVec(a) == _sortedVec(b);
426 if (visited.
contains(X))
return false;
439 if (!f.
contains(Y))
return std::nullopt;
465 _inner_br(dag, c,
true, reach0, reach1);
473 _inner_br(dag, p,
false, reach0, reach1);
493 for (
auto pa: dag.
parents(a)) {
494 _inner_br(dag, pa,
false, reach0, reach1);
530 if (Z.
empty())
return false;
bool existsArc(const Arc &arc) const
indicates whether a given arc exists
const NodeSet & parents(NodeId id) const
returns the set of nodes with arc ingoing to a given node
NodeSet children(const NodeSet &ids) const
returns the set of nodes which consists in the node and its parents returns the set of children of a ...
NodeSet ancestors(NodeId id) const
returns the set of all ancestors of id (nodes from which id is reachable)
NodeSet descendants(NodeId id) const
returns the set of all descendants of id (nodes reachable from id)
static bool _isMinimalBackdoorAdjustment(const DAG &dag, NodeId X, NodeId Y, const NodeSet &Z)
Check whether Z is a minimal backdoor adjustment set.
static bool _existsUnblockedDirectedPath_(const DAG &dag, NodeId X, NodeId Y, const NodeSet &Z, NodeSet &visited)
static NodeSetVec enumerateBackdoorSets(const DAG &dag, NodeId X, NodeId Y, const NodeSet &excluded_nodes=NodeSet(), std::size_t max_cardinality=0, bool only_minimal=true, bool stopAtFirst=false)
Enumerate valid backdoor adjustment sets.
static bool hasBackdoorPath(const DAG &dag, NodeId X, NodeId Y, const NodeSet &Z)
Test whether there exists an open backdoor path from X to Y given Z.
static NodeSetVec enumerateFrontdoorSets(const DAG &dag, NodeId X, NodeId Y, const NodeSet &excluded_nodes=NodeSet(), std::size_t max_cardinality=0, bool only_minimal=true, bool stopAtFirst=false)
Enumerate valid frontdoor adjustment sets.
static bool existsUnblockedDirectedPath(const DAG &dag, NodeId X, NodeId Y, const NodeSet &Z)
Check whether there exists a directed path X->..->Y unblocked by Z.
static std::optional< NodeSet > nodesOnDirectedPaths(const DAG &dag, NodeId X, NodeId Y)
Compute nodes lying on some directed path from X to Y.
static bool satisfiesFrontdoorCriterion(const DAG &dag, NodeId X, NodeId Y, const NodeSet &Z)
Check if Z satisfies the frontdoor criterion relative to (X, Y).
static bool satisfiesBackdoorCriterion(const DAG &dag, NodeId X, NodeId Y, const NodeSet &Z)
Check if Z satisfies the backdoor criterion relative to (X, Y).
std::vector< NodeSet > NodeSetVec
Convenience type: list of candidate adjustment sets.
static NodeSet backdoorReach(const DAG &dag, NodeId X)
Compute the "backdoor reach" of a node.
static bool _isMinimalFrontdoorAdjustment(const DAG &dag, NodeId X, NodeId Y, const NodeSet &Z)
Check whether Z is a minimal frontdoor adjustment set.
const NodeGraphPart & nodes() const
return *this as a NodeGraphPart
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 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.
bool contains(const Key &k) const
Indicates whether a given elements belong to the set.
bool empty() const noexcept
Indicates whether the set is the empty set.
void insert(const Key &k)
Inserts a new element into the set.
void erase(const Key &k)
Erases an element from the set.
Door criteria (backdoor/frontdoor) utilities for a DAG.
Size NodeId
Type for node ids.
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
gum is the global namespace for all aGrUM entities