52 std::vector< std::string > names;
53 for (
const auto& v: vars) {
56 std::ranges::sort(names);
58 if (names.empty()) {
return ""; }
59 if (names.size() == 1) {
return names[0]; }
60 if (names.size() == 2) {
return names[0] +
" and " + names[1]; }
63 for (
size_t i = 0; i < names.size(); ++i) {
64 if (i > 0) { os += (i + 1 == names.size() ?
", and " :
", "); }
73 std::string os = std::format(
"No causal effect of {} on {} because they are d-separated "
74 "after removing incoming edges into {}",
78 if (!knowing.
empty()) {
87 for (
const auto x: xset) {
88 const auto parents = out.parents(x);
89 for (
const auto p: parents)
90 out.eraseArc(
Arc(p, x));
95 template < GUM_Numeric GUM_SCALAR >
97 std::vector< std::string > names;
99 names.push_back(
cm.nameFromId(
id));
101 std::ranges::sort(names);
102 std::string out =
"[";
103 for (
size_t i = 0; i < names.size(); ++i) {
104 if (i > 0) out +=
", ";
105 out +=
"'" + names[i] +
"'";
111 template < GUM_Numeric GUM_SCALAR >
121 template < GUM_Numeric GUM_SCALAR >
126 for (
const auto& n: names)
131 template < GUM_Numeric GUM_SCALAR >
135 if (std::any_of(a.
begin(), a.
end(), [&b, &c](
const auto& x) {
136 return b.contains(x) || c.contains(x);
140 if (std::any_of(b.
begin(), b.
end(), [&c](
const auto& x) { return c.contains(x); })) {
150 template < GUM_Numeric GUM_SCALAR >
155 bool directDoCalculus) :
159 template < GUM_Numeric GUM_SCALAR >
164 bool directDoCalculus) :
170 template < GUM_Numeric GUM_SCALAR >
171 CausalFormula< GUM_SCALAR >
176 bool directDoCalculus) {
179 "The 3 parts of the query (on, doing, knowing) must be pairwise disjoint.");
188 if (!directDoCalculus) {
191 const auto& Xname = *
doing.begin();
192 const auto& Yname = *
on.begin();
193 const auto Xid =
cm.idFromName(Xname);
194 const auto Yid =
cm.idFromName(Yname);
198 auto optZ =
cm.backDoor(Xid, Yid);
207 return CausalFormula< GUM_SCALAR >(
cm,
212 std::string(
"backdoor ")
220 if (optZ.has_value() && !optZ->empty()) {
222 DoCalculus< GUM_SCALAR > dc(cm);
224 return CausalFormula< GUM_SCALAR >(cm,
229 std::string(
"frontdoor ")
239 auto ast = std::make_unique< ASTposteriorProba< GUM_SCALAR > >(cm.
observationalBN(),
254 std::unique_ptr< ASTtree< GUM_SCALAR > > ast
264 "Identified via do-calculus (ID/IDC).");
265 }
catch (
const NotImplementedYet&) {
273 "Effect not identifiable with available methods (do-calculus not yet implemented).");
274 }
catch (
const HedgeException& e) {
280 std::string(
"Effect not identifiable: ") + e.
what());
284 template < GUM_Numeric GUM_SCALAR >
290 bool directDoCalculus) {
298 template < GUM_Numeric GUM_SCALAR >
303 for (
const auto& [k, v]: values) {
305 const auto& var = tensor.variable(k);
309 }
catch (
const gum::NotFound&) {
320 template < GUM_Numeric GUM_SCALAR >
321 std::tuple< CausalImpact< GUM_SCALAR >, Tensor< GUM_SCALAR >, std::string >
331 Tensor< GUM_SCALAR > numeric;
335 if (!values.
empty() && numeric.nbrDim() > 0) {
338 numeric = numeric.extract(I);
344 return std::make_tuple(std::move(ci), std::move(numeric), std::move(expl));
347 template < GUM_Numeric GUM_SCALAR >
352 template < GUM_Numeric GUM_SCALAR >
357 template < GUM_Numeric GUM_SCALAR >
359 std::string_view doOperatorSuffix)
const {
363 template < GUM_Numeric GUM_SCALAR >
365 std::string_view doOperatorSuffix)
const {
369 template < GUM_Numeric GUM_SCALAR >
374 template < GUM_Numeric GUM_SCALAR >
379 template < GUM_Numeric GUM_SCALAR >
384 template < GUM_Numeric GUM_SCALAR >
389 template < GUM_Numeric GUM_SCALAR >
394 template < GUM_Numeric GUM_SCALAR >
399 template < GUM_Numeric GUM_SCALAR >
404 template < GUM_Numeric GUM_SCALAR >
409 template < GUM_Numeric GUM_SCALAR >
414 template < GUM_Numeric GUM_SCALAR >
419 template < GUM_Numeric GUM_SCALAR >
Root abstract node for the AST of algebraic expressions.
The base class for all directed edges.
Builds a CausalFormula for a query (d-sep -> backdoor -> frontdoor -> (optional) do-calculus).
static CausalFormula< GUM_SCALAR > _buildFromIds_(const CausalModel< GUM_SCALAR > &cm, const NodeSet &on, const NodeSet &doing, const NodeSet &knowing, bool directDoCalculus)
static bool _disjoint_(const Set< std::string > &a, const Set< std::string > &b, const Set< std::string > &c)
CausalFormula< GUM_SCALAR > _resultFormula_
Identified symbolic formula. If not identifiable, its AST may be nullptr and its explanation string (...
const NodeSet & on() const
std::string toLatex(std::string_view doOperatorPrefix="do(", std::string_view doOperatorSuffix=")") const
Generates a full LaTeX equation: Query = Formula.
const CausalFormula< GUM_SCALAR > & getResult() const
Access the underlying CausalFormula result.
static Set< std::string > _idsToNames_(const CausalModel< GUM_SCALAR > &cm, const NodeSet &ids)
std::string toString() const
Generates a string representation of the formula's AST.
std::vector< std::string > doingNames() const
Tensor< GUM_SCALAR > eval() const
Evaluates the formula's AST to compute the resulting probability distribution.
const ASTtree< GUM_SCALAR > & root() const
Access the root AST node of the identified formula.
CausalImpact(const CausalModel< GUM_SCALAR > &cm, const Set< std::string > &on, const Set< std::string > &doing, const Set< std::string > &knowing=Set< std::string >(), bool directDoCalculus=false)
Constructs a CausalImpact object using variable names.
std::string latexQuery(std::string_view doOperatorPrefix="do(", std::string_view doOperatorSuffix=")") const
Generates a LaTeX representation of the original query, e.g., P(Y | do(X), Z).
const NodeSet & knowing() const
static CausalFormula< GUM_SCALAR > _buildFromNames_(const CausalModel< GUM_SCALAR > &cm, const Set< std::string > &on, const Set< std::string > &doing, const Set< std::string > &knowing, bool directDoCalculus)
static NodeSet _namesToIds_(const CausalModel< GUM_SCALAR > &cm, const Set< std::string > &names)
std::vector< std::string > onNames() const
Convenience: return names corresponding to stored node ids (sorted).
const NodeSet & doing() const
bool isIdentified() const noexcept
Whether the causal effect has been identified.
bool _directDoCalculus_
If true, skip backdoor/frontdoor and use do-calculus directly.
const std::string & explanation() const
std::vector< std::string > knowingNames() const
const CausalModel< GUM_SCALAR > & cm() const
A causal model pairing an observational BayesNet with a causal DAG.
DAG causalDAG() const
Causal DAG (observed + latent variables), with node names set.
std::optional< NodeSet > frontDoor(NodeId cause, NodeId effect) const
Find a frontdoor adjustment set (Z) between cause and effect (IDs only).
const BayesNet< GUM_SCALAR > & observationalBN() const
Observational BN (observed variables only).
Instance-based do-calculus utilities bound to a single CausalModel.
FormulaPtr doCalculusWithObservation(const NodeSet &on, const NodeSet &doing, const NodeSet &knowing) const
IDC: identify P(on | do(doing), knowing).
FormulaPtr getFrontDoorTree(NodeId cause, NodeId effect, const NodeSet &zset) const
FormulaPtr doCalculus(const NodeSet &on, const NodeSet &doing) const
Thin wrapper around ID: doCalculus(on, doing).
FormulaPtr getBackDoorTree(NodeId cause, NodeId effect, const NodeSet &zset) const
GUM_NODISCARD const char * what() const noexcept override
bool empty() const noexcept
Indicates whether the hash table is empty.
Class for assigning/browsing values to tuples of discrete variables.
Instantiation & chgVal(const DiscreteVariable &v, Idx newval)
Assign newval to variable v in the Instantiation.
void add(const DiscreteVariable &v) final
Adds a new variable in the Instantiation.
Exception: at least one argument passed to a function is not what was expected.
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 const iterator & end() noexcept
The usual unsafe end iterator to parse the set.
bool empty() const noexcept
Indicates whether the set is the empty set.
iterator begin() const
The usual unsafe begin iterator to parse the set.
void insert(const Key &k)
Inserts a new element into the set.
#define GUM_ERROR(type, msg)
Size Idx
Type for indexes.
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
gum is the global namespace for all aGrUM entities
std::string _dsepExplanation_(const Set< std::string > &on, const Set< std::string > &doing, const Set< std::string > &knowing)
std::string _formatVarsForSentence_(const Set< std::string > &vars)
std::string _formatNodeSetNames_(const CausalModel< GUM_SCALAR > &cm, const NodeSet &zset)
DAG _removeIncomingIntoLocal_(const DAG &g, const NodeSet &xset)
Instantiation makeInstantiationFromValues(const Tensor< GUM_SCALAR > &tensor, const HashTable< std::string, std::string > &values)
Creates an instance for a tensor based on a HashTable.
std::tuple< CausalImpact< GUM_SCALAR >, Tensor< GUM_SCALAR >, std::string > causalImpact(const CausalModel< GUM_SCALAR > &cm, const Set< std::string > &on, const Set< std::string > &doing, const Set< std::string > &knowing=Set< std::string >(), const HashTable< std::string, std::string > &values=HashTable< std::string, std::string >())
Standalone helper that mirrors the Python function causalImpact(...).