pub struct CausalInferenceEngine {
pub graph: CausalGraph,
pub max_path_length: usize,
}Expand description
Production-grade causal inference engine.
§Example
use ipfrs_tensorlogic::{
CausalInferenceEngine, CausalNode, CausalEdge, Intervention,
};
let mut engine = CausalInferenceEngine::new(10);
engine.add_node(CausalNode::new("X", 0.0, 1.0)).expect("example: should succeed in docs");
engine.add_node(CausalNode::new("Y", 0.0, 1.0)).expect("example: should succeed in docs");
engine.add_edge(CausalEdge::direct("X", "Y", 0.8)).expect("example: should succeed in docs");
let result = engine.do_calculus(
&Intervention::new("X", 1.0),
&ipfrs_tensorlogic::CausalNodeId::new("Y"),
);
assert!((result.mean - 0.8).abs() < 1e-9);Fields§
§graph: CausalGraphThe underlying causal graph.
max_path_length: usizeMaximum number of hops considered when enumerating paths.
Implementations§
Source§impl CausalInferenceEngine
impl CausalInferenceEngine
Sourcepub fn new(max_path_length: usize) -> Self
pub fn new(max_path_length: usize) -> Self
Create a new engine with an empty graph and the given path-length limit.
Sourcepub fn add_node(&mut self, node: CausalNode) -> Result<(), CausalError>
pub fn add_node(&mut self, node: CausalNode) -> Result<(), CausalError>
Add a node to the graph.
Returns CausalError::NodeAlreadyExists if the identifier is taken.
Sourcepub fn add_edge(&mut self, edge: CausalEdge) -> Result<(), CausalError>
pub fn add_edge(&mut self, edge: CausalEdge) -> Result<(), CausalError>
Add a directed edge to the graph.
Both endpoints must already exist, and the edge must not introduce a directed cycle. On success the parent/child lists of both endpoints are updated in-place.
Sourcepub fn remove_node(&mut self, id: &CausalNodeId) -> bool
pub fn remove_node(&mut self, id: &CausalNodeId) -> bool
Remove a node and all edges that touch it.
Returns true if the node existed and was removed, false otherwise.
Sourcepub fn has_path(&self, from: &CausalNodeId, to: &CausalNodeId) -> bool
pub fn has_path(&self, from: &CausalNodeId, to: &CausalNodeId) -> bool
Return true if there is at least one directed path from from to to
(depth-first search, respects max_path_length).
Sourcepub fn is_ancestor(
&self,
ancestor: &CausalNodeId,
descendant: &CausalNodeId,
) -> bool
pub fn is_ancestor( &self, ancestor: &CausalNodeId, descendant: &CausalNodeId, ) -> bool
Return true if ancestor is a strict ancestor of descendant
(i.e. there is a directed path from ancestor to descendant).
Sourcepub fn ancestors(&self, id: &CausalNodeId) -> Vec<CausalNodeId>
pub fn ancestors(&self, id: &CausalNodeId) -> Vec<CausalNodeId>
Return all strict ancestors of id via BFS through parent pointers.
Sourcepub fn descendants(&self, id: &CausalNodeId) -> Vec<CausalNodeId>
pub fn descendants(&self, id: &CausalNodeId) -> Vec<CausalNodeId>
Return all strict descendants of id via BFS through child pointers.
Sourcepub fn all_directed_paths(
&self,
from: &CausalNodeId,
to: &CausalNodeId,
) -> Vec<Vec<CausalNodeId>>
pub fn all_directed_paths( &self, from: &CausalNodeId, to: &CausalNodeId, ) -> Vec<Vec<CausalNodeId>>
Enumerate all directed paths from from to to up to
max_path_length hops (DFS with backtracking).
Sourcepub fn backdoor_paths(
&self,
from: &CausalNodeId,
to: &CausalNodeId,
) -> Vec<Vec<CausalNodeId>>
pub fn backdoor_paths( &self, from: &CausalNodeId, to: &CausalNodeId, ) -> Vec<Vec<CausalNodeId>>
Enumerate backdoor paths from from to to.
A backdoor path is any path that arrives at from via an incoming
edge (i.e. starts from a parent of from and eventually reaches to).
Paths are limited to max_path_length hops.
Sourcepub fn do_calculus(
&self,
intervention: &Intervention,
target: &CausalNodeId,
) -> InferenceResult
pub fn do_calculus( &self, intervention: &Intervention, target: &CausalNodeId, ) -> InferenceResult
Compute the interventional distribution P(target | do(intervention)).
Uses a linear causal model: the mean of target under the intervention
is the intervention value times the sum of all path effects from the
intervened node to target. The posterior variance shrinks by the
total explained fraction (capped at 0.99 to avoid degenerate zero
variance), and the confidence is the explained fraction clamped to
[0, 1].
Sourcepub fn counterfactual(&self, query: &CounterfactualQuery) -> InferenceResult
pub fn counterfactual(&self, query: &CounterfactualQuery) -> InferenceResult
Estimate the counterfactual distribution of query.target had
query.intervention been applied, conditioned on query.evidence.
The implementation uses do-calculus as a base and adds an evidence
correction: for each observed variable in evidence we sum the product
of its observed value and the direct edge strength to the target.
Sourcepub fn average_causal_effect(
&self,
from: &CausalNodeId,
to: &CausalNodeId,
value1: f64,
value2: f64,
) -> f64
pub fn average_causal_effect( &self, from: &CausalNodeId, to: &CausalNodeId, value1: f64, value2: f64, ) -> f64
Compute the Average Causal Effect (ACE) of from on to.
ACE = E[to | do(from = value2)] - E[to | do(from = value1)]
Sourcepub fn confounders(
&self,
x: &CausalNodeId,
y: &CausalNodeId,
) -> Vec<CausalNodeId>
pub fn confounders( &self, x: &CausalNodeId, y: &CausalNodeId, ) -> Vec<CausalNodeId>
Return the common ancestors of x and y (i.e. potential confounders).
Sourcepub fn is_d_separated(
&self,
x: &CausalNodeId,
y: &CausalNodeId,
given: &[CausalNodeId],
) -> bool
pub fn is_d_separated( &self, x: &CausalNodeId, y: &CausalNodeId, given: &[CausalNodeId], ) -> bool
Simplified d-separation check.
Returns true if x and y are d-separated given the conditioning
set given.
The implementation tests:
- No direct edge from
xtoy(after removing given nodes). - No directed path from
xtoythat does not pass through a given node. - No backdoor path from
xtoythat is not blocked by a given node.
Sourcepub fn stats(&self) -> CausalStats
pub fn stats(&self) -> CausalStats
Compute summary statistics for the current graph.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for CausalInferenceEngine
impl RefUnwindSafe for CausalInferenceEngine
impl Send for CausalInferenceEngine
impl Sync for CausalInferenceEngine
impl Unpin for CausalInferenceEngine
impl UnsafeUnpin for CausalInferenceEngine
impl UnwindSafe for CausalInferenceEngine
Blanket Implementations§
impl<T> Allocation for T
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more