diff --git a/src/CausalInference.jl b/src/CausalInference.jl index b4be5b6..80c61c4 100644 --- a/src/CausalInference.jl +++ b/src/CausalInference.jl @@ -4,7 +4,7 @@ using Graphs.SimpleGraphs using Combinatorics using Base.Iterators -export ancestors, descendants, alt_test_dsep, test_covariate_adjustment, alt_test_backdoor, find_dsep, find_min_dsep, find_covariate_adjustment, find_backdoor_adjustment, find_min_covariate_adjustment, find_frontdoor_adjustment, list_dseps, list_covariate_adjustment, list_backdoor_adjustment, list_frontdoor_adjustment +export ancestors, descendants, alt_test_dsep, test_covariate_adjustment, alt_test_backdoor, find_dsep, find_min_dsep, find_covariate_adjustment, find_backdoor_adjustment, find_min_covariate_adjustment, find_min_backdoor_adjustment, find_frontdoor_adjustment, list_dseps, list_covariate_adjustment, list_backdoor_adjustment, list_frontdoor_adjustment export dsep, skeleton, gausscitest, dseporacle, partialcor export unshielded, pcalg, vskel export cpdag, alt_cpdag diff --git a/src/gensearch.jl b/src/gensearch.jl index 2c8377f..9686b4b 100644 --- a/src/gensearch.jl +++ b/src/gensearch.jl @@ -175,6 +175,8 @@ Follows the algorithmic approach proposed in https://arxiv.org/abs/1803.00116. """ function find_backdoor_adjustment(g, X, Y, I = Set{eltype(g)}(), R = setdiff(Set(vertices(g)), X, Y)) bdZ = setdiff(find_covariate_adjustment(g, X, Y, I, R), descendants(g, X, no_incoming(X))) + # we generalize bd to sets by testing (X indep Y given Z) in G with outgoing edges from X removed + # instead of checking the bd criterion for pairs of vertices (x in X and y in Y) as originally proposed by Pearl which is more restrictive if issubset(I, bdZ) && alt_test_dsep(g, X, Y, bdZ, no_outgoing(X)) return bdZ else @@ -194,6 +196,16 @@ function find_min_covariate_adjustment(g, X, Y, I = Set{eltype(g)}(), R = setdif return find_min_dsep(g, X, Y, I, setdiff(R, descendants(g, PCPXY)), (pe, ne, v, w) -> v in X && w in PCPXY && ne == RIGHT) end +""" + find_min_backdoor_adjustment(g, X, Y, I = Set{eltype(g)}(), R = setdiff(Set(vertices(g)), X, Y)) + +Find an inclusion minimal backdoor adjustment set `Z` with `I subseteq Z subseteq R` for sets of vertices `X` and `Y` in `g`, else return `false`. + +""" +function find_min_backdoor_adjustment(g, X, Y, I = Set{eltype(g)}(), R = setdiff(Set(vertices(g)), X, Y)) + return find_min_dsep(g, X, Y, I, setdiff(R, descendants(g, X)), (pe, ne, v, w) -> v in X && ne == RIGHT) +end + """ find_frontdoor_adjustment(g, X, Y, I = Set{eltype(g)}(), R = setdiff(Set(vertices(g)), X, Y)) diff --git a/test/gensearch.jl b/test/gensearch.jl index a705b77..03a6e1a 100644 --- a/test/gensearch.jl +++ b/test/gensearch.jl @@ -8,7 +8,7 @@ Y = Set(4) # for some of the tests other results would not be wrong per se # e.g. for the finding methods, other valid sets could be returned -# however, the algorithms should be deterministic, so I think the +# however, the algorithms should be deterministic, so we think the # tests are okay for now @testset "gensearch in1" begin @@ -31,6 +31,7 @@ Y = Set(4) @test find_covariate_adjustment(g, X, Y) == Set([5,6]) @test find_backdoor_adjustment(g, X, Y) == Set([5,6]) @test find_min_covariate_adjustment(g, X, Y) == Set(5) + @test find_min_backdoor_adjustment(g, X, Y) == Set(5) @test find_frontdoor_adjustment(g, X, Y) == Set([2,3,7]) @test Set(list_dseps(g, X, Y)) == Set([Set([3,6]), Set([2,6]), Set([2,3,6]), Set([3,6,7]), Set([2,6,7]), Set([2,3,6,7]), Set([3,5]), Set([2,5]), Set([2,3,5]), Set([3,5,7]), Set([2,5,7]), Set([2,3,5,7]), Set([3,5,6]), Set([2,5,6]), Set([2,3,5,6]), Set([3,5,6,7]), Set([2,5,6,7]), Set([2,3,5,6,7])]) @test Set(list_covariate_adjustment(g, X, Y)) == Set([Set([5,7]), Set([5]), Set([6]), Set([6,7]), Set([5,6]), Set([5,6,7])])