Skip to content

Commit e9bae30

Browse files
authored
Add Dor & Tasi PDAG completion algorithm (#112)
* Add Dor & Tasi * Update src/pdag.jl * Make it non-breaking
1 parent 3c6710f commit e9bae30

File tree

5 files changed

+57
-3
lines changed

5 files changed

+57
-3
lines changed

docs/src/library.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ CausalInference.meek_rule2
3131
CausalInference.meek_rule3
3232
CausalInference.meek_rule4
3333
pdag2dag!
34+
pdag_to_dag_dortasi!
35+
pdag_to_dag_meek!
3436
```
3537

3638
## PC algorithm

src/CausalInference.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export plot_pc_graph_recipes, plot_fci_graph_recipes # if GraphRecipes is loaded
2525
export plot_pc_graph_tikz, plot_fci_graph_tikz # if TikzGraphs is loaded
2626
export orient_unshielded, orientable_unshielded, apply_pc_rules
2727
export ges
28-
export pdag2dag!
28+
export pdag2dag!, pdag_to_dag_meek!, pdag_to_dag_dortasi!
2929

3030
#include("pinv.jl")
3131
include("graphs.jl")

src/meek.jl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,11 @@ function meek_rule4(dg, v, w)
108108
end
109109

110110
"""
111-
pdag2dag!(g, rule4=false)
111+
pdag_to_dag_meek!(g, rule4=false)
112112
113113
Complete PDAG to DAG using meek_rules.
114114
"""
115-
function pdag2dag!(g, rule4=false)
115+
function pdag_to_dag_meek!(g, rule4=false)
116116
while true
117117
# find unoriented edge
118118
for e in edges(g) # go through edges (bad to start in the beginning?)
@@ -127,4 +127,9 @@ function pdag2dag!(g, rule4=false)
127127
@label orient
128128
meek_rules!(g; rule4)
129129
end
130+
g
130131
end
132+
"""
133+
Deprecated alias for `pdag_to_dag_meek!`.
134+
"""
135+
const pdag2dag! = pdag_to_dag_meek!

src/pdag.jl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,40 @@ Children of x in g are vertices y such that there is a directed edge y <-- x.
147147
Returns sorted array.
148148
"""
149149
children(g, x) = setdiff(outneighbors(g, x), inneighbors(g, x))
150+
151+
"""
152+
pdag_to_dag_dortasi!!(g)
153+
154+
Complete PDAG to DAG using Dor & Tasi (1992).
155+
"""
156+
function pdag_to_dag_dortasi!(g)
157+
removed = falses(nv(g)) # Mark vertices removed from (sub-)graph A. Efficient if degree small?
158+
while !all(removed)
159+
touched = false
160+
for x in vertices(g)
161+
removed[x] && continue
162+
for y in outneighbors(g, x)
163+
removed[y] && continue
164+
has_edge(g, y, x) || @goto skip # not a sink
165+
end
166+
for y in neighbors_undirected(g, x)
167+
removed[y] && continue
168+
for z in inneighbors(g, x) # contains all adjacents by assumption
169+
removed[z] && continue
170+
y==z || isadjacent(g, y, z) || @goto skip
171+
end
172+
end
173+
for y in copy(outneighbors(g, x))
174+
removed[y] && continue
175+
rem_edge!(g, x, y)
176+
end
177+
touched = true
178+
removed[x] = true
179+
@label skip
180+
end
181+
if !touched
182+
error("PDAG has no consistent extension to a DAG")
183+
end
184+
end
185+
return g
186+
end

test/cpdag.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ for stable in (true, false)
5757

5858
h1 = pc_oracle(g; stable)
5959
h2 = cpdag(g)
60+
61+
g2 = pdag_to_dag_dortasi!(copy(h2))
62+
@test !is_cyclic(g2)
63+
@test h2 == cpdag(g2)
64+
65+
g2 = pdag_to_dag_meek!(copy(h2))
66+
@test !is_cyclic(g2)
67+
@test h2 == cpdag(g2)
68+
69+
6070
h1 == h2 || println(vpairs(g))
6171
@test vpairs(h1) vpairs(h2)
6272
@test vpairs(h2) vpairs(h1)

0 commit comments

Comments
 (0)