Source code for y0.algorithm.do_calculus

"""Do Calculus."""

from typing import Annotated

from .conditional_independencies import are_d_separated
from ..dsl import Variable
from ..graph import NxMixedGraph
from ..util import InPaperAs

__all__ = [
    "rule_2_of_do_calculus_applies",
]


# TODO implement rule 1 condition
# TODO implement rule 3 condition


[docs] def rule_2_of_do_calculus_applies( graph: Annotated[NxMixedGraph, InPaperAs("G")], *, treatments: Annotated[set[Variable], InPaperAs(r"\mathbf{X}")], outcomes: Annotated[set[Variable], InPaperAs(r"\mathbf{Y}")], conditions: Annotated[set[Variable], InPaperAs(r"\mathbf{Z}")], condition: Variable, ) -> bool: r"""Check if Rule 2 of the Do-Calculus applies to the conditioned variable. :param graph: The graph :param treatments: The treatments :param conditions: The conditions :param outcomes: The outcomes :param condition: The condition to check :returns: If rule 2 applies, see below. If Rule 2 of the do calculus applies to the conditioned variable, then it can be converted to a do variable. .. math:: \newcommand\ci{\perp\!\!\!\perp} \newcommand{\ubar}[1]{\underset{\bar{}}{#1}} \newcommand{\obar}[1]{\overset{\bar{}}{#1}} \text{if } (\exists Z \in \mathbf{Z})(\mathbf{Y} \ci Z | \mathbf{X}, \mathbf{Z} - \{Z\})_{G_{\bar{\mathbf{X}}\ubar{Z}}} \\ \text{then } P(\mathbf{Y}|do(\mathbf{X}),\mathbf{Z}) = P(\mathbf Y|do(\mathbf X), do(Z), \mathbf{Z} - \{Z\}) """ reduced_conditions = treatments | (conditions - {condition}) reduced_graph: Annotated[NxMixedGraph, InPaperAs(r"G_{\bar{x}, \underbar{z}}")] = ( graph.remove_in_edges(treatments).remove_out_edges(condition) ) return all( are_d_separated(reduced_graph, outcome, condition, conditions=reduced_conditions) for outcome in outcomes )