CausalStructures changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.7.1 - 2026-09-24
New features
- Implemented
markov_blanketfor aPAG. enumerate_magshas aselection_biaskeyword;selection_bias = falsereturns only the MAGs without undirected edges, pruning those candidates from the search.adjustment_set(::DAG)andadjustment_set(::AbstractPDAG)withtype = :optimalnow warn when some node ofyis not a (possible) descendant ofx, since the O-set is not defined there.- Estimands returned by
id/idc/idp/cidpare simplified further.
Bug fixes
markov_blanketon anAbstractAGorADMGmissed nodes reachable through collider paths (e.g.CinA <-> B <-> C), so it could return a set too small to separatenodefrom the rest of the graph.meek_closure's R4 was missing the precondition thatamust be adjacent tod, so it could orienta --> bin cases not actually implied by the pattern.- The adjustment functions (
is_valid_adjustment,all_adjustment_sets,adjustment_set) could reject valid adjustment sets and return a non-optimal set in several cases:- On an
AbstractPDAGorPAG, nodes were treated as lying on a causal path fromxtoywhen they do not (e.g.BinB --- X --> Y). - On an
MPDAG, the separation step moralized the proper backdoor graph, which is only correct for CPDAGs.is_valid_adjustmentandall_adjustment_setsnow check amenability explicitly and block definite-status paths directly. - With several treatments on a
DAG,ADMG,AGorMAG, a node was treated as causal when it reachesyonly through another treatment (e.g.WinX1 --> W --> X2 --> Ywithx = [:X1, :X2]). This affectedis_valid_adjustment,all_adjustment_sets, andadjustment_set(::DAG; type = :optimal).
- On an
backdoor_seton aCPDAGcould return an invalid set (e.g.[]forX,YinX --- A --> Y, X --> Y).is_valid_iv/all_iv_setsaccepted a confounded descendant ofxas an instrument (e.g.ZinX --> Z, X --> Y, U --> X + Y).possible_joint_parent_setscould return joint parent sets that no DAG in the class realizes.apply_background_knowledgeaccepted background knowledge inconsistent with the graph (e.g.A --> B, C --> BonA --- B --- C) and returned a graph with a new v-structure. It now errors in those cases.
Performance improvements
- Improved performance of
dag_from_pdagby using the potential-sink worklist algorithm from Wienöbst, Bannach & Liśkiewicz (UAI 2021), instead of rescanning every remaining node after each removal.
0.7.0 - 2026-09-19
Breaking changes
plot's visual defaults (colors, linewidths, etc) are no longer configurable viaPreferences.jl. Instead, set a project-wide default with a Makie theme, e.g.Makie.set_theme!(CausalGraphPlot = (node_color = :lightblue,)).A per-edge style
Dict(e.g.edge_color) no longer treats a bare node name as "every edge touching this node"; it now only matches aCausalEdge, a(src, dst)tuple, an edge-type symbol, or:default.plot's node-label keywordslabels,label_color,label_fontsize, andlabel_fontare renamed tonode_labels,node_label_color,node_label_fontsize, andnode_label_font, for consistency with thenode_*/edge_*naming used elsewhere.condition_marginalize's keywordscond_vars/marg_varsare renamed togiven/index, matching thegivenkeyword used byidc/cidp/proband theindexargument used bymarginal.
New features
Support of Makie themes:
plot'sedge_colorandedge_label_colornow inherit the active Makie theme'slinecolor/textcolorwhen not given explicitly, so e.g.Makie.set_theme!(Makie.theme_dark())keeps edges and edge labels visible against a dark figure.Automatic edge routing via dummy nodes (from Sugiyama) now work with
stretch_to_fig=true.Implement idp and cidp for identifying causal effects from PAGs (Jaber et al. 2022), generalizing id/idc from ADMGs.
plotgainsedge_linestyle, styling an edge's own line (e.g. dashing<->edges to mark latent confounding, as is common in the literature).plotgainsedge_labels,edge_label_color,edge_label_fontsize,edge_label_font,edge_label_shift, andedge_label_distancefor drawing text along each edge, following its own angle.uniform_daggains acountskeyword (paired with the newuniform_dag_counts) to reuse a precomputed DP table across repeated draws at the samen(or smaller).
Performance improvements
- Improved performance of
all_frontdoor_sets/frontdoor_setby reusing scratch buffers across recursive calls and scanning only each node's actual neighbors. - Improved performance of
all_frontdoor_sets/frontdoor_set's step that filters out candidate nodes unable to satisfy the front-door criterion's third condition, by replacing its per-candidate reachability search with a single combined pass, for bothDAGandADMG. - Improved performance of
all_iv_setsby testing membership per candidate node instead of per combinatorial subset. - Improved performance of
possible_joint_parent_sets/possible_parent_setsby avoiding an expensive graph rebuild-and-validate per candidate orientation. - Improved performance of
condition_marginalizeandag_to_magby using a single-pass separator-existence check instead ofminimal_separator's full two-pass search.
0.6.0 - 2026-09-14
Breaking changes
plot's layout-algorithm keywords (e.g.seed,iterations) must now be passed aslayout_kwargs = (; seed = 1)instead of directly, sinceplotis now backed by a proper Makie recipe with a fixed set of attributes.plotnow returns aFigureAxisPlotinstead of aFigure.
New features
Added
backdoor_set(Generalized Backdoor Criterion) forADMG.CausalGraphnow supports==andhash, comparing graphs structurally (same class, nodes, and edges).plot!(ax, cg)draws aCausalGraphinto anAxisyou already own, so multiple graphs (or a graph and other plots) can share oneFigure.plot/plot!'s returned plot is fully reactive:plt.node_color[] = :redrestyles it in place, and node/label sizing keeps fitting the containingAxislive, including as it's resized.
Bug fixes
is_valid_adjustment/all_adjustment_setsonADMGandPAGcould wrongly validate an adjustment set when a node had two or more bidirected/circle edges to distinct confounders.plot'sedge_pathsoverride for one edge no longer discards automatic per-edge routing (e.g. fromlayout = :sugiyama) for the rest of the graph's edges.
Other changes
- Improved performance of
adjustment_set.
0.5.1 - 2026-09-11
New features
- Node-set arguments across the package (
x/y/z,include/restrict,latents,nodes, etc.) now also accept a singleSymbol, not justVector{Symbol}.
Bug fixes
is_valid_iv/all_iv_setson anADMGcould wrongly reject a valid instrument when its own edge into the treatment was bidirected (e.g.Z <-> X).possible_parent_sets/possible_optimal_adjustment_setson anMPDAGonly checked for a new collider at the target node, so it could wrongly accept a parent orientation that closes a directed cycle elsewhere in the graph.maximal_local_mag/possible_local_structures: Step 2 of the local-structure algorithm looked for a witness edge pointing out ofVlinstead of into it.meek_closure/is_mpdag: R1 wrongly skipped orientations that would create a new collider, and R4 used the wrong pattern, so both could leave a background-knowledge PDAG under-oriented.pagcauses/maximal_local_mag: could return wrong or spurious adjustment sets. Fixed and validated testing against brute-force approach.is_valid_backdoor/all_backdoor_setson aDAGwrongly accepted any set whenywas itself a parent ofx.The generalized adjustment criterion's forbidden set (
is_valid_adjustment/all_adjustment_setsonDAG/ADMG/AG/MAG/AbstractPDAG/PAG) excludedyinstead ofxfrom the causal-path nodes before taking descendants.
Other changes
Package now compiles under
--trim=safe(JuliaC).Improve documentation.
pagcausesnow parallelizes overThreads.nthreads()once there are enough candidates to be worth splitting across tasks.Improved performance of some adjustment set functions.
0.5.0 - 2026-09-05
Breaking changes
cgraph(...; class = T)is removed. Construct graphs by calling the graph type directly instead, e.g.DAG("A --> B"),ADMG("A --> B, A <-> B).
New features
plotnow supportsedge_paths, aDictoverriding an edge's drawn route with an explicit polyline instead ofcurvature/automatic routing.- Added a
:sugiyamalayout method for DAGs. Requriesusing Sugiyama, and if loaded is the default for DAGs.
0.4.0 - 2026-08-24
Breaking changes
plot'snode_shape:round/:boxare renamed to:circle/:square.
New features
plot'snode_shapenow supports:ellipse/:rectfor label-fit stretching.plotnow supports astretch_to_fig_sizeto stretch the layout to fillfig_sizeinstead of following the aspect of the layout.
Bug fixes
- Fixed
plotnode sizes being shrunk by an unrelated close node pair elsewhere in the graph. - Fixed
plot's automatic edge routing to use all nodes. - Fixed
plotclipping a curved edge at the canvas edge. - Fixed
plot'scurvaturebeing unable to force a straight edge to override the automatic routing.curvaturenow defaults tonothing(auto-route) so any explicit value now works correctly.
0.3.1 - 2026-08-18
New features
d_separated,m_separated,minimal_separator(DAG), and the backdoor/frontdoor/adjustment-set functions now accept aVector{Symbol}(in addition to a singleSymbol) forx/y, for querying sets of treatments/outcomes.Added
id/idc(Shpitser & Pearl's identification algorithm) forDAG/ADMG.Added
possible_parent_sets, the graph half of the local IDA algorithm, forAbstractPDAG.Added
backdoor_set(Generalized Backdoor Criterion, Maathuis & Colombo 2015) forDAG,CPDAG,MAG, andPAG.Added
possible_optimal_adjustment_sets(O-set-based IDA) andpossible_joint_parent_sets(joint-IDA) forAbstractPDAG.Added
possible_d_sep(D-SEP) forAbstractAG.Added
possible_local_structuresandmaximal_local_mag(Wang, Qin & Zhou 2023) forPAG.Added
pagcauses(PAGcauses, Wang, Tao, Qin & Zhou 2025), finding every valid adjustment set for aPAGwithout enumerating MAGs.New plot features:
plotgainednode_shape(:roundor:box), per node or for the whole graph. Both shapes are fitted to their label but rounded out to equal sides unless the label is oblong, so short labels give circles and squares while long ones give ellipses and rectangles. Edges clip to (and route around) the shape actually drawn.plotgainednode_linestyle, for dashed or dotted node borders.plotgainedlabels, overriding the text drawn in each node, so labels can carry spaces, subscripts, or several lines.plot'slayoutkeyword now also accepts aDictof positions keyed by node name, not just aVectorinnodes(cg)order.plotgainedcurvature, bowing an edge into an arc by a signed fraction of its length; per edge, per edge type, or for the whole graph. An explicitly curved edge overrides the automatic obstacle routing and parallel-edge fanning.plot's per-edge styleDicts accept aCausalEdgekey (e.g.bidirected(:X, :Y)) naming one exact edge, which is what separates the two edges of anADMG's shared pair. A(src, dst)tuple key now names an unordered node pair, matching either way round, so styling no longer requires knowing which way an edge is stored.
Bug fixes
- Parallel edges are now rejected on construction for every graph class except
UNKNOWN; previouslycgraph("X --> Y, X --> Y"; class = DAG)and friends were accepted. possible_ancestors/possible_descendantsonMPDAGcould include nodes only reachable via a partially directed cycle introduced by background knowledge; this also affectedis_valid_adjustment/all_adjustment_setsonMPDAG.
0.3.0 - 2026-08-10
Breaking changes
- Removed the built-in
:circlelayout.layout/plotnow require NetworkLayout to be loaded (or bring your own layout to plot), and default to:stress.
New features
- Added
adjustment_setforADMGandPAG, returning the smallest valid adjustment set. - Added
anteriors/posteriorsmethods forADMG. - Extended
condition_marginalizeto acceptADMG. - Added
check_cyclesandr4as keyword arguments tomeek_closure, which can be set to help speed it up. - Added
node_padding(and"plot_node_padding"preference) to control the padding between a node's label and its circle edge. - Added
arrow_fill(and"plot_edge_arrow_fill"preference) to style arrowheads independently ofedge_color, including hollow/outline-only arrowheads. - Added
fig_sizeto set the plot's figure size.
Bug fixes
dag_from_pdagcould pick a sink whose undirected neighbors were adjacent to each other but not to the sink's existing parents, which could make it introduce a v-structure absent from the input PDAG.
0.2.0 - 2026-08-04
Breaking changes
- Dropped the
simplekeyword argument fromcgraph. - Changed default layout to
:stressonce NetworkLayout is loaded.
New features
Implement separation for PAGs.
Extend adjustments to include DAG.
Add
class = PAGsupport togenerate_graph.Make
enumerate_magsuse several threads if available.
Other changes
- Improved and extended docs, and uses DocumenterCodeBlocks now.
0.1.0 - 2026-07-25
Initial release.