Package evaluation to test CausalStructures on Julia 1.14.0-DEV.2802 (918269a29b*) started at 2026-08-27T13:00:00.345 ################################################################################ # Set-up # Installing PkgEval dependencies (TestEnv)... Activating project at `~/.julia/environments/v1.14` Set-up completed after 15.38s ################################################################################ # Installation # Installing CausalStructures... Resolving package versions... Installed CausalStructures ─ v0.4.0 Updating `~/.julia/environments/v1.14/Project.toml` [b41ab49a] + CausalStructures v0.4.0 Updating `~/.julia/environments/v1.14/Manifest.toml` [b41ab49a] + CausalStructures v0.4.0 [21216c6a] + Preferences v1.5.2 [10745b16] + Statistics v1.11.1 [56f22d72] + Artifacts v1.11.0 [ade2ca70] + Dates v1.11.0 [8f399da3] + Libdl v1.11.0 [37e2e46d] + LinearAlgebra v1.14.0 [de0858da] + Printf v1.11.0 [9a3f8284] + Random v1.11.0 [ea8e919c] + SHA v1.13.0 [fa267f1f] + TOML v1.0.3 [4ec0a83e] + Unicode v1.11.0 [e66e0078] + CompilerSupportLibraries_jll v1.5.7+0 [4536629a] + OpenBLAS_jll v0.3.34+0 [8e850b90] + libblastrampoline_jll v5.15.0+0 Installation completed after 5.05s ################################################################################ # Precompilation # Precompiling PkgEval dependencies... Precompiling package dependencies... Precompiling project... 6.2 s ✓ CausalStructures 4.8 s ✓ NetworkLayout 52.0 s ✓ CausalStructures → MakieExt 3.2 s ✓ CausalStructures → NetworkLayoutExt 4 dependencies successfully precompiled in 68 seconds. 290 already precompiled. Precompilation completed after 97.11s ################################################################################ # Testing # Testing CausalStructures Status `/tmp/jl_2JQBBg/Project.toml` [4c88cf16] Aqua v0.8.16 [b41ab49a] CausalStructures v0.4.0 `~/.julia/packages/CausalStructures/8CFVQ/` [ee78f7c6] Makie v0.24.13 [46757867] NetworkLayout v0.4.10 [10745b16] Statistics v1.11.1 [f8b46487] TestItemRunner v1.3.1 [1c621080] TestItems v1.1.0 [9a3f8284] Random v1.11.0 [fa267f1f] TOML v1.0.3 [8dfed614] Test v1.11.0 Status `/tmp/jl_2JQBBg/Manifest.toml` [621f4979] AbstractFFTs v1.5.0 [1520ce14] AbstractTrees v0.4.5 [7d9f7c33] Accessors v0.1.45 [79e6a3ab] Adapt v4.7.0 [35492f91] AdaptivePredicates v1.2.0 [66dad0bd] AliasTables v1.1.3 [27a7e980] Animations v0.4.2 [4c88cf16] Aqua v0.8.16 [67c07d97] Automa v1.2.0 [13072b0f] AxisAlgorithms v1.1.0 [39de3d68] AxisArrays v0.4.8 [18cc8868] BaseDirs v1.4.0 [fa961155] CEnum v0.5.0 [96374032] CRlibm v1.0.2 [b41ab49a] CausalStructures v0.4.0 `~/.julia/packages/CausalStructures/8CFVQ/` [d360d2e6] ChainRulesCore v1.26.1 [6b39b394] CodecZstd v0.8.7 [a2cac450] ColorBrewer v0.4.2 [35d6a980] ColorSchemes v3.31.0 [3da002f7] ColorTypes v0.12.1 [c3611d14] ColorVectorSpace v0.11.0 [5ae59095] Colors v0.13.1 [38540f10] CommonSolve v0.2.14 [34da2185] Compat v4.18.1 [a33af91c] CompositionsBase v0.1.2 [95dc2771] ComputePipeline v0.1.8 [187b0558] ConstructionBase v1.6.0 [d38c429a] Contour v0.6.3 [b7a15901] CoreMath v0.1.0 [9a962f9c] DataAPI v1.16.0 [864edb3b] DataStructures v0.19.6 [e2d170a0] DataValueInterfaces v1.0.0 [927a84f5] DelaunayTriangulation v1.6.6 [31c24e10] Distributions v0.25.131 [ffbed154] DocStringExtensions v0.9.5 [4e289a0a] EnumX v1.0.7 [429591f6] ExactPredicates v2.2.9 [b86e33f2] FFTA v0.3.1 [5789e2e9] FileIO v1.20.0 [8fc22ac5] FilePaths v0.9.0 [48062228] FilePathsBase v0.9.24 [1a297f60] FillArrays v1.17.0 ⌅ [53c48c17] FixedPointNumbers v0.8.6 [1fa38f19] Format v1.3.7 [b38be410] FreeType v4.1.1 [663a7486] FreeTypeAbstraction v0.10.8 [a0844989] Gamma v1.2.0 [5c1252a2] GeometryBasics v0.5.11 [3955a311] GridLayoutBase v0.11.2 [34004b35] HypergeometricFunctions v0.3.30 [2803e5a7] ImageAxes v0.6.12 [c817782e] ImageBase v0.1.7 [a09fc81d] ImageCore v0.10.5 [82e4d734] ImageIO v0.6.9 [bc367c6b] ImageMetadata v0.9.10 [9b13fd28] IndirectArrays v1.0.0 [d25df0c9] Inflate v0.1.5 [18e54dd8] IntegerMathUtils v0.1.4 [a98d9a8b] Interpolations v0.16.3 [d1acc4aa] IntervalArithmetic v1.0.11 [8197267c] IntervalSets v0.7.14 [3587e190] InverseFunctions v0.1.17 [92d709cd] IrrationalConstants v0.2.6 [f1662d9f] Isoband v0.1.1 [c8e1da08] IterTools v1.10.0 [82899510] IteratorInterfaceExtensions v1.0.0 [692b3bcd] JLLWrappers v1.8.0 [682c06a0] JSON v1.7.1 [b835a17e] JpegTurbo v0.1.6 [5ab0869b] KernelDensity v0.6.12 [b964fa9f] LaTeXStrings v1.4.1 [8cdb02fc] LazyModules v0.3.1 [2ab3a3ac] LogExpFunctions v1.0.1 [1914dd2f] MacroTools v0.5.16 [ee78f7c6] Makie v0.24.13 [dbb5928d] MappedArrays v0.4.3 [0a4f8689] MathTeXEngine v0.6.9 [e1d29d7a] Missings v1.2.0 [e94cdb99] MosaicViews v0.3.4 [46d2c3a1] MuladdMacro v0.2.7 [f09324ee] Netpbm v1.1.1 [46757867] NetworkLayout v0.4.10 [510215fc] Observables v0.5.5 [6fe1bfb0] OffsetArrays v1.17.0 [52e1d378] OpenEXR v0.3.3 [bac558e1] OrderedCollections v2.0.1 [90014a1f] PDMats v0.11.41 [f57f5aa1] PNGFiles v0.4.5 [19eb6ba3] Packing v0.5.1 [5432bcbf] PaddedViews v0.5.12 ⌅ [69de0a69] Parsers v2.8.7 [eebad327] PkgVersion v0.3.3 [995b91a9] PlotUtils v1.4.4 [647866c9] PolygonOps v0.1.2 [aea7be01] PrecompileTools v1.3.4 [21216c6a] Preferences v1.5.2 [27ebfcd6] Primes v0.5.7 [92933f4c] ProgressMeter v1.11.0 [43287f4e] PtrArrays v1.4.0 [4b34888f] QOI v1.0.2 [1fd47b50] QuadGK v2.11.3 [b3c3ace0] RangeArrays v0.3.2 [c84ed2f1] Ratios v0.4.5 [189a3867] Reexport v1.2.2 [05181044] RelocatableFolders v1.0.1 [ae029012] Requires v1.3.1 [79098fc4] Rmath v0.9.0 [f2b01f46] Roots v3.0.7 [5eaf0fd0] RoundingEmulator v0.2.1 [fdea26ae] SIMD v3.7.2 [6c6a2e73] Scratch v1.3.0 [65257c39] ShaderAbstractions v0.5.0 [73760f76] SignedDistanceFields v0.4.1 [699a6c99] SimpleTraits v0.9.6 [45858cf5] Sixel v0.1.5 [a2af1166] SortingAlgorithms v1.2.3 [276daf66] SpecialFunctions v2.9.0 [860ef19b] StableRNGs v1.0.4 [cae243ae] StackViews v0.1.2 [90137ffa] StaticArrays v1.9.19 [1e83bf80] StaticArraysCore v1.4.4 [10745b16] Statistics v1.11.1 [82ae8749] StatsAPI v1.8.0 [2913bbd2] StatsBase v0.34.13 [4c63d2b9] StatsFuns v2.2.1 [09ab397b] StructArrays v0.7.3 [ec057cc2] StructUtils v2.8.5 [3783bdb8] TableTraits v1.0.1 [bd369af6] Tables v1.14.0 [62fd8b95] TensorCore v0.1.1 [f8b46487] TestItemRunner v1.3.1 [1c621080] TestItems v1.1.0 [731e570b] TiffImages v0.11.9 [3bb67fe8] TranscodingStreams v0.11.3 [981d1d27] TriplotBase v0.1.0 [1cfade01] UnicodeFun v0.4.1 [1986cc42] Unitful v1.28.0 [e3aaa7dc] WebP v0.1.3 [efce3f68] WoodburyMatrices v1.1.0 [6e34b625] Bzip2_jll v1.0.9+0 [4e9b3aee] CRlibm_jll v1.0.1+0 [83423d85] Cairo_jll v1.18.7+0 [a38c48d9] CoreMath_jll v0.1.0+0 ⌅ [5ae413db] EarCut_jll v2.2.4+0 [2e619515] Expat_jll v2.8.3+0 ⌅ [b22a6f82] FFMPEG_jll v8.1.2+0 [a3f928ae] Fontconfig_jll v2.17.1+0 [d7e528f0] FreeType2_jll v2.14.3+1 [559328eb] FriBidi_jll v1.0.17+0 ⌅ [b0724c58] GettextRuntime_jll v0.22.4+0 ⌅ [59f7168a] Giflib_jll v5.2.3+0 [7746bdde] Glib_jll v2.88.3+0 [3b182d85] Graphite2_jll v1.3.16+0 ⌅ [2e76f6c2] HarfBuzz_jll v8.5.1+0 [905a6f67] Imath_jll v3.2.2+0 [aacddb02] JpegTurbo_jll v3.2.0+1 [c1c5ebd0] LAME_jll v3.100.3+0 [88015f11] LERC_jll v4.1.0+0 [1d63c593] LLVMOpenMP_jll v22.1.7+0 ⌅ [e9f186c6] Libffi_jll v3.4.7+0 [7e76a0d4] Libglvnd_jll v1.7.1+1 [94ce4f54] Libiconv_jll v1.18.0+0 [4b2f31a3] Libmount_jll v2.42.0+0 [89763e89] Libtiff_jll v4.7.3+0 [38a345b3] Libuuid_jll v2.42.0+0 [e7412a2a] Ogg_jll v1.3.6+0 [6cdc7f73] OpenBLASConsistentFPCSR_jll v0.3.34+0 [18a262bb] OpenEXR_jll v3.4.14+0 [efe28fd5] OpenSpecFun_jll v0.5.6+0 [91d4177d] Opus_jll v1.6.1+0 [30392449] Pixman_jll v0.46.4+0 [f50d1b31] Rmath_jll v0.5.2+0 [ffd25f8a] XZ_jll v5.8.3+0 [4f6342f7] Xorg_libX11_jll v1.8.13+0 [0c0b7dd1] Xorg_libXau_jll v1.0.13+0 [a3789734] Xorg_libXdmcp_jll v1.1.6+0 [1082639a] Xorg_libXext_jll v1.3.8+0 [d091e8ba] Xorg_libXfixes_jll v6.0.2+0 [ea2f1a96] Xorg_libXrender_jll v0.9.12+0 [a65dc6b1] Xorg_libpciaccess_jll v0.19.0+0 [c7cfdc94] Xorg_libxcb_jll v1.17.1+0 [c5fb5394] Xorg_xtrans_jll v1.6.0+0 [9a68df92] isoband_jll v0.2.3+0 [a4ae2306] libaom_jll v3.14.1+0 [0ac62f75] libass_jll v0.17.4+0 [8e53e030] libdrm_jll v2.4.134+0 [f638f0a6] libfdk_aac_jll v2.0.4+0 [b53b4c65] libpng_jll v1.6.58+0 [075b6546] libsixel_jll v1.10.5+0 [9a156e7d] libva_jll v2.23.0+0 [f27f6e37] libvorbis_jll v1.3.8+0 [c5f90fcd] libwebp_jll v1.6.0+0 ⌅ [1270edf5] x264_jll v10164.0.1+0 [dfaa095f] x265_jll v4.1.0+0 [0dad84c5] ArgTools v1.2.0 [56f22d72] Artifacts v1.11.0 [2a0f44e3] Base64 v1.11.0 [8bf52ea8] CRC32c v1.11.0 [ade2ca70] Dates v1.11.0 [8ba89e20] Distributed v1.11.0 [f43a241f] Downloads v1.7.0 [7b1f6079] FileWatching v1.11.0 [b77e0a4c] InteractiveUtils v1.11.0 [ac6e5ff7] JuliaSyntaxHighlighting v1.13.0 [b27032c2] LibCURL v1.0.0 [76f85450] LibGit2 v1.11.0 [8f399da3] Libdl v1.11.0 [37e2e46d] LinearAlgebra v1.14.0 [56ddb016] Logging v1.11.0 [d6f4376e] Markdown v1.11.0 [a63ad114] Mmap v1.11.0 [ca575930] NetworkOptions v1.3.0 [44cfe95a] Pkg v1.14.0 [de0858da] Printf v1.11.0 [3fa0cd96] REPL v1.11.0 [9a3f8284] Random v1.11.0 [ea8e919c] SHA v1.13.0 [9e88b42a] Serialization v1.11.0 [1a1011a3] SharedArrays v1.11.0 [6462fe0b] Sockets v1.11.0 [2f01184e] SparseArrays v1.13.0 [f489334b] StyledStrings v1.13.0 [4607b0f0] SuiteSparse [fa267f1f] TOML v1.0.3 [a4e569a6] Tar v1.10.0 [8dfed614] Test v1.11.0 [cf7118a7] UUIDs v1.11.0 [4ec0a83e] Unicode v1.11.0 [e66e0078] CompilerSupportLibraries_jll v1.5.7+0 [deac9b47] LibCURL_jll v8.21.0+0 [e37daf67] LibGit2_jll v1.9.6+0 [29816b5a] LibSSH2_jll v1.11.103+0 [14a3606d] MozillaCACerts_jll v2026.7.16 [4536629a] OpenBLAS_jll v0.3.34+0 [05823500] OpenLibm_jll v0.8.7+0 [458c3c95] OpenSSL_jll v3.5.7+0 [efcefdf7] PCRE2_jll v10.47.0+0 [bea87d4a] SuiteSparse_jll v7.10.1+0 [83775a58] Zlib_jll v1.3.2+0 [3161d3a3] Zstd_jll v1.5.7+1 [8e850b90] libblastrampoline_jll v5.15.0+0 [8e850ede] nghttp2_jll v1.69.0+0 [3f19e933] p7zip_jll v17.8.0+0 Info Packages marked with ⌅ have new versions available but compatibility constraints restrict them from upgrading. Testing Running tests... Test Summary: | Pass Total Time CausalStructures | 53642 53642 11m38.4s test | 53642 53642 11m37.9s Aqua.jl | 11 11 1m11.5s Aqua | 11 11 1m11.5s Method ambiguity | 1 1 6.7s Unbound type parameters | 1 1 0.2s Undefined exports | 1 1 0.0s Compare Project.toml and test/Project.toml | 1 1 0.4s Stale dependencies | 1 1 3.7s Compat bounds | 4 4 0.7s Piracy | 1 1 0.6s Persistent tasks | 1 1 36.2s test-admg.jl | 51 51 24.6s is_admg identifies ADMG graphs | 3 3 8.4s ADMG rejects undirected edges | 1 1 0.6s ADMG rejects directed cycles | 1 1 0.0s parents and children work for ADMG (directed edges only) | 4 4 1.2s neighbors for ADMG includes bidirected adjacency | 1 1 0.0s ancestors follows directed edges only in ADMG | 1 1 0.7s descendants follows directed edges only in ADMG | 1 1 0.6s no ancestors via bidirected edges in ADMG | 1 1 0.0s spouses returns bidirected neighbors | 2 2 0.2s spouses returns empty for nodes with no bidirected edges | 2 2 0.0s districts returns c-components | 1 1 0.3s districts with only directed edges gives singletons | 2 2 0.1s m_separated works for chain | 2 2 1.8s m_separated works for collider | 2 2 0.0s m_separated handles bidirected confounding | 2 2 0.0s markov_blanket district-based for ADMG | 3 3 0.7s markov_blanket includes parents of district members for ADMG | 3 3 0.0s exogenous_nodes works for ADMG | 1 1 0.3s is_valid_adjustment: classic confounding L-->X-->Y, L-->Y | 3 3 2.6s is_valid_adjustment: rejects forbidden descendants | 2 2 0.0s all_adjustment_sets: finds minimal set | 1 1 4.0s all_adjustment_sets: with extra non-confounding node | 3 3 0.4s all_adjustment_sets: no valid set when all paths blocked by collider | 1 1 0.0s adjustment_set ADMG: returns valid set, prefers smaller | 2 2 0.5s adjustment_set ADMG: empty set valid | 2 2 0.0s is_valid_adjustment ADMG: accepts Vector{Symbol} for x and y | 4 4 2.0s test-ag.jl | 58 58 19.4s AG: directed chain constructs | 2 2 4.1s AG: undirected chain constructs | 1 1 0.0s AG: bidirected edge constructs | 1 1 0.0s AG: rejects directed cycle | 1 1 0.0s AG: rejects undirected + arrowhead at same node | 2 2 0.0s AG: rejects anterior constraint violation (directed) | 1 1 0.0s AG: parents and children | 3 3 1.5s AG: neighbors includes all edge types | 2 2 0.0s AG: ancestors follow directed edges only, ignoring undirected | 4 4 0.6s AG: descendants follow directed edges only, ignoring undirected | 3 3 0.7s AG: anteriors follow parents and undirected | 2 2 0.9s AG: posteriors follow children and undirected | 2 2 1.0s AG: exogenous_nodes returns nodes with no parents | 1 1 0.3s AG: spouses returns bidirected neighbors | 4 4 0.4s AG: markov_blanket includes parents, children, co-parents, spouses, undirected | 1 1 0.7s is_ag: AG is always an AG | 1 1 0.1s is_ag: DAG is an AG | 1 1 0.0s is_ag: ADMG with anterior violation is not an AG | 1 1 0.9s is_ag: ADMG without anterior violations is an AG | 1 1 0.0s AG: subgraph returns induced AG | 3 3 0.3s m_separated on DAG matches d_separated: chain | 2 2 1.2s m_separated on DAG matches d_separated: collider | 2 2 0.0s m_separated AG: directed chain | 2 2 1.5s m_separated AG: directed collider | 2 2 0.0s m_separated AG: bidirected edge | 1 1 0.0s m_separated AG: undirected chain | 2 2 0.0s m_separated AG: undirected non-collider blocked by conditioning | 1 1 0.0s m_separated AG: pure bidirected chain uses anteriors | 2 2 0.0s m_separated AG: empty conditioning set | 2 2 0.0s minimal_separator AG: directed chain | 1 1 1.3s minimal_separator AG: undirected chain | 1 1 0.0s minimal_separator AG: unblockable bidirected | 1 1 0.0s minimal_separator AbstractAG: accepts Vector{Symbol} for x and y | 2 2 3.9s test-backdoor.jl | 112 112 37.5s is_valid_backdoor: canonical choices on ECI graph | 5 5 1.3s all_backdoor_sets: minimal sets on ECI graph | 3 3 2.6s all_backdoor_sets: non-minimal with max_size=2 | 6 6 0.2s all_backdoor_sets: empty set valid when v-structure blocks backdoor | 2 2 0.2s is_valid_backdoor: mediator graph | 2 2 0.0s all_backdoor_sets: mediator graph returns only empty set | 2 2 0.0s is_valid_backdoor: collider-driven candidates | 4 4 0.0s all_backdoor_sets: collider graph non-minimal | 3 3 0.1s is_valid_backdoor: chain graph empty set valid | 2 2 0.0s adjustment_set: parents type returns Pa(X) \ {X,Y} | 1 1 4.3s adjustment_set: backdoor type returns a valid backdoor set | 2 2 0.0s adjustment_set: backdoor type is minimal, unlike parents type | 2 2 0.0s adjustment_set: backdoor type falls back to parents when Y is a direct cause of X | 1 1 0.0s adjustment_set: backdoor type valid when parent is not ancestor of Y | 2 2 0.0s adjustment_set: optimal type returns K on ECI graph | 2 2 0.0s adjustment_set: optimal default on simple confounder | 2 2 0.0s adjustment_set: optimal empty on chain | 3 3 0.0s adjustment_set: unknown type throws ArgumentError | 1 1 0.0s is_valid_adjustment DAG: simple confounder | 2 2 1.0s is_valid_adjustment DAG: chain has valid empty set | 1 1 0.0s is_valid_adjustment DAG: descendant of X is forbidden | 2 2 0.0s is_valid_adjustment DAG: agrees with is_valid_backdoor on ECI graph | 4 4 0.0s all_adjustment_sets DAG: finds {A} for simple confounder | 1 1 1.3s all_adjustment_sets DAG: chain returns empty set | 2 2 0.0s all_adjustment_sets DAG: consistent with is_valid_adjustment | 2 2 0.1s is_valid_adjustment: simple confounder (DAG-as-MAG) | 2 2 4.6s is_valid_adjustment: confounder visible via extra witness parent | 2 2 0.0s is_valid_adjustment: bidirected confounder | 2 2 0.0s is_valid_adjustment: collider structure blocks without conditioning | 2 2 0.0s is_valid_adjustment: descendant of X is forbidden | 2 2 0.0s is_valid_adjustment: bare edge has no witness, no valid set | 1 1 0.0s all_adjustment_sets: bidirected confounder returns {A} and {M} | 1 1 1.8s all_adjustment_sets: collider structure returns only empty set | 2 2 0.0s all_adjustment_sets: bare edge has no valid set | 1 1 0.0s all_adjustment_sets: consistent with is_valid_adjustment | 2 2 0.1s proper backdoor graph removes causal edges | 2 2 0.0s adjustment_set AbstractAG: returns valid set, prefers smaller | 2 2 0.5s adjustment_set AbstractAG: empty set valid | 2 2 0.0s is_valid_backdoor (ADMG): confounder A blocks backdoor | 2 2 0.2s is_valid_backdoor (ADMG): descendant of X rejected | 1 1 0.0s is_valid_backdoor (ADMG): bidirected confounder requires adjustment | 1 1 0.0s is_valid_backdoor (ADMG): consistent with DAG latent projection | 2 2 2.4s all_backdoor_sets (ADMG): finds valid adjustment sets | 3 3 2.6s all_backdoor_sets (ADMG): consistent with DAG latent projection | 1 1 0.8s all_backdoor_sets (ADMG): latent X-Y confounder is not identifiable | 1 1 0.0s is_valid_backdoor DAG: accepts Vector{Symbol} for x and y | 3 3 0.9s is_valid_backdoor ADMG: accepts Vector{Symbol} for x and y | 2 2 0.3s all_backdoor_sets: accepts Vector{Symbol} for x and y | 1 1 0.4s is_valid_adjustment DAG: accepts Vector{Symbol} for x and y | 2 2 0.3s all_adjustment_sets DAG: accepts Vector{Symbol} for x and y | 1 1 0.1s adjustment_set DAG: accepts Vector{Symbol} for x and y | 6 6 2.3s adjustment_set AbstractPDAG: accepts Vector{Symbol} for x and y | 2 2 8.7s is_valid_adjustment MAG: accepts Vector{Symbol} for x and y | 2 2 0.2s test-background-knowledge.jl | 56 56 25.6s BackgroundKnowledge: construction from edges and string | 8 8 1.0s BackgroundKnowledge: string reversed markers | 2 2 0.0s BackgroundKnowledge: fan-out with + in string | 2 2 0.9s BackgroundKnowledge: invalid inputs | 7 7 0.1s cgraph rejects forbidden edges | 3 3 0.2s dag_to_mpdag: empty background knowledge matches dag_to_cpdag | 3 3 12.3s dag_to_mpdag: required edge propagates via Meek R1 | 3 3 0.2s dag_to_mpdag: forbidden edge orients the reverse direction | 1 1 0.0s dag_to_mpdag: partial knowledge leaves other edges undirected | 2 2 0.1s dag_to_mpdag: background knowledge inconsistent with DAG errors | 3 3 0.0s dag_to_mpdag: enumerate_dags respects background knowledge | 6 6 10.2s apply_background_knowledge: on a CPDAG directly | 2 2 0.0s apply_background_knowledge: no-op and error cases | 6 6 0.0s apply_background_knowledge: incremental refinement of an MPDAG | 3 3 0.3s BackgroundKnowledge and ForbiddenEdge printing | 5 5 0.3s test-enumerate-dags.jl | 31 31 3.2s enumerate_dags: chain A--B--C has 3 DAGs, none is A->B<-C | 5 5 0.9s count_dags: chain A--B--C returns 3 | 1 1 0.1s enumerate_dags: v-structure A->B<-C returns singleton | 3 3 0.0s count_dags: v-structure A->B<-C returns 1 | 1 1 0.0s enumerate_dags: undirected triangle has 6 DAGs (all distinct) | 2 2 0.6s count_dags: undirected triangle returns 6 | 1 1 0.0s enumerate_dags: v-structure plus undirected branch forced by Meek R1 | 4 4 0.0s count_dags: v-structure plus undirected branch returns 1 | 1 1 0.0s enumerate_dags: two independent chains multiply | 1 1 0.0s count_dags: two independent chains returns 6 | 1 1 0.0s enumerate_dags: empty graph returns 1 DAG (the empty DAG) | 2 2 0.1s enumerate_dags count matches count_dags | 1 1 0.0s enumerate_dags: accepts CPDAG input | 2 2 0.1s _enumerate_dags_threaded matches enumerate_dags | 3 3 0.9s _count_dags_threaded matches count_dags | 1 1 0.2s _dag_enum_frontier resolves the whole MEC when smaller than target | 2 2 0.2s test-enumerate-mags.jl | 17 17 18.0s enumerate_mags: all-circle 2-path has 8 members | 1 1 13.7s enumerate_mags: collider PAG has 4 members | 1 1 0.0s enumerate_mags: an edgeless PAG has a single member | 1 1 0.0s enumerate_mags: undirected 4-cycle PAG has a single member | 2 2 0.2s enumerate_mags: handles a PAG with an o-- edge | 3 3 1.0s enumerate_mags: every member maps back to the PAG | 4 4 0.2s enumerate_mags: contains the originating MAG | 1 1 0.4s enumerate_mags: contains the mag_from_pag representative | 1 1 0.3s enumerate_mags: members are pairwise distinct | 1 1 0.5s _enumerate_mags_threaded matches the sequential result | 2 2 1.7s test-enumerate-subsets.jl | 5 5 3.2s _search_subsets_threaded matches _search_subsets_sequential | 2 2 2.0s _search_subsets_threaded: checker rejecting everything yields no sets | 1 1 0.5s _search_subsets_threaded: min_size restricts subset sizes | 2 2 0.7s test-estimand.jl | 59 59 7.9s prob sorts and de-duplicates variables | 4 4 0.7s prob drops conditioned variables from the head | 1 1 0.0s prob prints with and without a conditioning set | 2 2 0.1s prob with an empty head is one | 3 3 0.1s marginal with an empty index is the identity | 1 1 0.2s marginal flattens nested sums | 3 3 0.3s marginal prints its index set | 1 1 0.4s product flattens, drops ones, and collapses singletons | 5 5 0.9s empty product is the multiplicative identity | 3 3 0.2s product preserves factor order when printing | 1 1 0.0s quotient with a unit denominator collapses | 1 1 0.2s quotient prints as a ratio | 2 2 0.4s quotient collapses a ratio of probabilities to a conditional | 4 4 0.0s marginal over part of the head marginalizes the term | 3 3 0.0s printing parenthesizes non-atomic subterms | 3 3 1.3s marginal pulls constant factors out of the sum | 1 1 0.0s marginal drops a factor that sums to one | 2 2 0.0s marginal keeps a factor another factor still depends on | 2 2 0.0s marginal pulls a constant denominator out of the sum | 2 2 0.0s quotient cancels a factor shared by both sides | 3 3 0.2s estimands hash consistently with equality | 3 3 0.8s estimands of different shapes are not equal | 3 3 0.0s _freshen renames a sum that shadows a free variable | 1 1 1.1s _freshen seeds the walk with free variables, not just reserved ones | 1 1 0.0s _freshen lets disjoint scopes reuse a name | 1 1 0.1s _freshen leaves a non-shadowing sum alone | 1 1 0.2s latex rendering | 2 2 0.7s test-frontdoor.jl | 66 66 14.7s is_valid_frontdoor: M satisfies criterion on classic graph | 1 1 1.0s is_valid_frontdoor: empty Z fails when directed path exists | 1 1 0.0s is_valid_frontdoor: U fails condition (i) - does not intercept X -> M -> Y | 1 1 0.0s is_valid_frontdoor: condition (ii) fails when backdoor path from X to Z exists | 1 1 0.0s is_valid_frontdoor: condition (iii) fails when X does not block backdoor from Z to Y | 1 1 0.0s is_valid_frontdoor: X --> Y direct edge violates condition (i) | 2 2 0.0s is_valid_frontdoor: chain mediators - each singleton is valid | 3 3 0.0s is_valid_frontdoor: no causal path - empty Z valid | 1 1 0.0s is_valid_frontdoor: Jeong Fig 1b - four valid sets | 4 4 0.0s is_valid_frontdoor: Jeong Fig 1b - invalid sets | 4 4 0.0s GETCAND2NDFDC: Jeong (2022) Example 2 - D excluded, A B C retained | 2 2 0.4s GETCAND2NDFDC: Jeong (2022) Example 2 - infeasible when D ∈ I | 1 1 0.1s GETCAND3RDFDC: Jeong (2022) Example 3 - all of R' retained | 2 2 1.9s GETCAND3RDFDC: Jeong (2022) Example 3 - infeasible when v in I fails GETDEP | 1 1 0.1s GETDEP: Jeong (2022) Example 4 - T={A} | 2 2 0.2s GETDEP: Jeong (2022) Example 4 - T={B} | 2 2 0.2s GETDEP: Jeong (2022) Example 4 - T={C} | 2 2 0.2s GETDEP: Jeong (2022) Example 5 - R'={B,C}, T={B} returns nothing | 1 1 0.1s GETCAUSALPATHGRAPH: Jeong (2022) Example 7 - node set | 1 1 1.1s GETCAUSALPATHGRAPH: Jeong (2022) Example 7 - edges | 6 6 0.2s FindFDSet: Jeong (2022) Example 1 - include={}, restrict={A,B,C,D} | 2 2 0.7s FindFDSet: Jeong (2022) Example 1 - I={C}, R={A,C} | 2 2 0.1s FindFDSet: Jeong (2022) Example 1 - I={D}, R={A,B,C,D} infeasible | 1 1 0.0s ListFDSets: classic single mediator | 1 1 0.7s ListFDSets: Jeong (2022) Fig. 1b - all 4 valid sets | 1 1 0.0s ListFDSets: Jeong (2022) Fig. 1b - required C restricts listing | 1 1 0.0s ListFDSets: Jeong (2022) Fig. 1b - required D returns empty | 1 1 0.0s ListFDSets: Jeong (2022) Fig. 6a - 9 valid sets (3^2) | 2 2 0.0s ListFDSets: Jeong (2022) Fig. 6b - 27 valid sets (3^3) | 1 1 0.0s is_valid_frontdoor (ADMG): classic front-door with bidirected confounder | 2 2 1.2s is_valid_frontdoor (ADMG): M confounded with X fails condition (ii) | 1 1 0.0s is_valid_frontdoor (ADMG): consistent with DAG latent projection | 2 2 0.0s frontdoor_set (ADMG): classic front-door with bidirected confounder | 1 1 3.8s frontdoor_set/all_frontdoor_sets (ADMG): consistent with DAG latent projection on Fig. 1b | 2 2 0.1s frontdoor_set/all_frontdoor_sets (ADMG): consistent with DAG latent projection on Fig. 6a | 2 2 0.0s all_frontdoor_sets (ADMG): condition 3 requires marrying a directed parent with a bidirected spouse | 1 1 0.0s is_valid_frontdoor: accepts Vector{Symbol} for x and y | 2 2 1.0s frontdoor_set/all_frontdoor_sets: accepts Vector{Symbol} for x and y | 2 2 1.4s test-gbc.jl | 22 22 14.9s backdoor_set DAG: classic confounder | 2 2 0.2s backdoor_set DAG: no parents gives empty set | 1 1 0.0s backdoor_set DAG: agrees with a valid adjustment set when it exists | 2 2 0.0s backdoor_set CPDAG: unshielded colliders protect the parents | 1 1 0.4s backdoor_set CPDAG: undirected edge to Y makes Y a possible descendant | 1 1 0.0s backdoor_set CPDAG: Y a parent of X has no generalized back-door set | 1 1 0.0s backdoor_set: no method for MPDAG or plain PDAG (unproven scope) | 2 2 0.7s backdoor_set CPDAG: agrees with is_valid_adjustment when it exists | 2 2 0.2s backdoor_set MAG: confounder blocks the backdoor path | 2 2 2.1s backdoor_set MAG: invisible edge is not identifiable | 1 1 0.0s backdoor_set MAG: bidirected edge unrelated to Y needs no adjustment | 1 1 0.0s backdoor_set MAG: rejects graphs with undirected (selection-variable) edges | 1 1 0.0s backdoor_set PAG: agrees with the underlying MAG when the class is fully resolved | 3 3 11.2s backdoor_set PAG: circle uncertainty at X can make no set identifiable | 1 1 0.0s backdoor_set PAG: rejects graphs with undirected (selection-variable) edges | 1 1 0.0s test-graph-string.jl | 51 51 7.5s cgraph string: simple directed chain | 5 5 0.2s cgraph string: fan-out with + | 4 4 0.0s cgraph string: fan-in with + | 3 3 0.0s cgraph string: multiple statements separated by comma | 3 3 0.0s cgraph string: fan-out on both sides of a marker (full cartesian product) | 6 6 2.1s cgraph string: mixed isolated node, fan-out, and chain across statements | 7 7 1.7s cgraph string: reversed directed marker | 3 3 0.0s cgraph string: undirected marker | 2 2 2.6s cgraph string: bidirected marker | 2 2 0.0s cgraph string: reversed partial markers normalize like other reversed markers | 2 2 0.4s cgraph string: partial markers | 4 4 0.1s cgraph string: isolated nodes | 3 3 0.2s cgraph string: matches equivalent programmatic construction | 2 2 0.1s cgraph string: newline-separated statements | 2 2 0.0s cgraph string: invalid graph for class throws | 1 1 0.0s cgraph string: malformed syntax throws ArgumentError | 2 2 0.0s test-id.jl | 29 29 4.8s id: no confounding gives the conditional | 1 1 2.5s id: back-door graph gives the g-formula | 1 1 0.0s id: front-door graph | 1 1 0.1s id: bow arc is not identifiable | 1 1 0.0s id: instrument does not identify nonparametrically | 1 1 0.0s id: latent projection of a confounded DAG reproduces the bow arc | 1 1 0.0s id: a DAG argument is treated as an ADMG | 1 1 0.0s id: joint outcomes and multiple interventions | 2 2 0.3s id: effect on a non-descendant is the marginal | 1 1 0.0s id: identifiable effect in a graph with two districts | 2 2 0.0s id: reproduces the worked example of Shpitser & Pearl (2008) | 3 3 0.8s id: Q[S] conditionals become ratios of marginals | 2 2 0.3s id: rejects malformed queries | 5 5 0.0s idc: rule 2 moves the conditioning variable into the intervention | 1 1 0.5s idc: with an empty conditioning set it reduces to id | 1 1 0.2s idc: front-door graph conditioned on the mediator | 1 1 0.0s idc: inherits unidentifiability from id | 1 1 0.0s idc: rejects overlapping argument sets | 3 3 0.0s test-iv.jl | 31 31 4.3s is_valid_iv: Z is valid instrument in classic IV graph | 1 1 0.3s is_valid_iv: confounder U fails exclusion restriction | 1 1 0.0s is_valid_iv: empty set fails relevance condition | 1 1 0.0s is_valid_iv: X and Y are rejected from z | 2 2 0.0s is_valid_iv: isolated node fails relevance | 1 1 0.0s is_valid_iv: direct effect Z --> Y violates exclusion restriction | 1 1 0.0s is_valid_iv: set with multiple valid instruments | 3 3 0.0s is_valid_iv: instrument with path through confounder is invalid | 1 1 0.0s all_iv_sets: returns the single valid instrument | 2 2 1.3s all_iv_sets: returns multiple minimal IV sets | 3 3 0.3s all_iv_sets: non-minimal includes supersets | 3 3 0.5s all_iv_sets: no valid IV when all paths to X are confounded | 1 1 0.0s is_valid_iv (ADMG): Z is valid instrument with bidirected confounder | 1 1 0.2s is_valid_iv (ADMG): isolated node fails relevance | 3 3 0.0s is_valid_iv (ADMG): bidirected Z <-> Y violates exclusion restriction | 1 1 0.0s all_iv_sets (ADMG): finds the valid instrument | 2 2 1.2s all_iv_sets (ADMG): consistent with DAG latent projection | 1 1 0.0s is_valid_iv/all_iv_sets: accepts Vector{Symbol} for y | 3 3 0.2s test-layout.jl | 1 1 0.3s layout: unknown method errors with a helpful message | 1 1 0.3s test-local-structure.jl | 10 10 5.8s maximal_local_mag matches Fig. 1 of Wang, Qin & Zhou (2023) end to end | 1 1 2.9s possible_local_structures rejects sets that aren't pairwise adjacent | 3 3 2.0s maximal_local_mag: empty local structure directs all circles away from x | 1 1 0.4s maximal_local_mag: c = {A} orients X's arrow at the A end only | 1 1 0.1s _pa_mask returns parents, not children | 2 2 0.3s possible_local_structures and maximal_local_mag reject graphs with undirected (selection-variable) edges | 2 2 0.0s test-mag-to-pag.jl | 31 31 1.0s mag_to_pag: returns an UNKNOWN graph | 2 2 0.0s mag_to_pag: preserves the skeleton | 1 1 0.1s mag_to_pag: edge count matches the MAG | 1 1 0.0s mag_to_pag: unshielded collider gets invariant arrowheads (docstring) | 2 2 0.1s mag_to_pag: collider from a latent-free DAG | 3 3 0.0s mag_to_pag: directed chain has no invariant marks | 2 2 0.0s mag_to_pag: fork is equivalent to the chain | 2 2 0.0s mag_to_pag: single directed edge has no invariant marks | 1 1 0.0s mag_to_pag: single bidirected edge has no invariant marks | 1 1 0.0s mag_to_pag: R1 propagates a tail off a collider | 3 3 0.0s mag_to_pag: is deterministic | 1 1 0.0s mag_to_pag: discriminating path orients the collider (R4) | 2 2 0.0s mag_to_pag: discriminating path orients the non-collider (R4) | 2 2 0.0s mag_to_pag: R4 distinguishes non-equivalent MAGs | 2 2 0.2s mag_to_pag: discriminating path with an intermediate parent vertex orients the collider (R4) | 1 1 0.0s mag_to_pag: discriminating path with an intermediate parent vertex orients the non-collider (R4) | 1 1 0.0s _pag_rule_r10!: fires with two disjoint uncovered p.d. paths to gamma's parents | 2 2 0.2s _pag_rule_r10!: does not fire when the two paths' first vertices are adjacent | 2 2 0.1s test-mag.jl | 476 476 5.6s MAG: directed chain constructs | 3 3 0.0s MAG: bidirected-only constructs | 1 1 0.0s MAG: rejects directed cycle | 1 1 0.0s MAG: rejects AG anterior constraint violation | 1 1 0.0s MAG: rejects non-maximal AG (inducing path between non-adjacent nodes) | 1 1 0.0s is_mag: canonical MAG example | 1 1 0.2s is_mag: canonical non-MAG example (inducing path Y-W) | 1 1 0.0s MAG: m_separated works via AbstractAG dispatch | 2 2 0.0s MAG: ancestors and descendants work | 2 2 0.8s MAG: markov_blanket works | 1 1 0.3s MAG: minimal_separator works | 1 1 0.3s MAG: parents and children work | 2 2 0.1s MAG: spouses and exogenous_nodes work | 2 2 0.0s is_mag: MAG is always a MAG | 1 1 0.0s is_mag: DAG is a MAG | 1 1 0.0s is_mag: AG that satisfies maximality is a MAG | 1 1 0.0s is_mag: AG that violates maximality is not a MAG | 1 1 0.0s ag_to_mag: already-maximal AG is returned unchanged | 3 3 0.9s ag_to_mag: canonical non-maximal adds Y <-> W | 4 4 0.0s ag_to_mag: AG that is MAG returns itself | 2 2 0.0s ag_to_mag: adds directed edge when ancestor relationship holds | 2 2 0.0s MAG maximality check agrees with direct minimal_separator on random graphs | 442 442 2.8s test-makie-ext.jl | 93 93 5m09.5s Makie.plot: draws every edge type without error | 1 1 4m02.0s Makie.plot: routes an edge around an obstacle node | 1 1 2.7s Makie.plot: fans out multiple edges between the same pair | 1 1 2.7s Makie.plot: resolves per-edge and per-node style dicts | 2 2 8.7s Makie.plot: title options | 2 2 4.9s Makie.plot: accepts a custom position vector, errors on length mismatch | 2 2 1.2s Makie.plot: errors on an empty graph | 1 1 0.1s Makie.plot: explicit geometry keyword overrides | 1 1 1.6s Makie.plot: text-fit node sizing grows for longer labels | 3 3 1.7s MakieExt: node sizing rounds out to equal sides for short labels | 6 6 0.2s MakieExt: _stretch_to_aspect stretches the narrower bbox dimension to match the target | 6 6 1.1s Makie.plot: node-wide edge_color/arrow_fill Dict overrides every edge touching a node | 7 7 2.4s Makie.plot: arrow_fill defaults to edge color and accepts hollow arrowheads | 3 3 6.2s Makie.plot: NetworkLayout output with far-flung isolated nodes doesn't blow up figure size | 2 2 3.7s Makie.plot: outer_margin and title_gap keywords | 2 2 2.5s Makie.plot: node shapes render, and unknown shapes error | 4 4 2.5s MakieExt: node boundary geometry per shape | 17 17 0.2s Makie.plot: custom and multi-line labels | 3 3 2.7s Makie.plot: node_linestyle draws a dashed border | 2 2 5.7s Makie.plot: layout accepts positions keyed by node name | 2 2 2.5s Makie.plot: edges clip to non-circular node outlines | 2 2 0.2s MakieExt: curvature bows an edge, signed relative to src --> dst | 4 4 0.1s Makie.plot: curvature accepts a scalar and a Dict | 3 3 9.3s Makie.plot: explicit curvature is not overridden by routing or fanning | 3 3 2.3s MakieExt: a CausalEdge key names one exact edge | 6 6 2.2s MakieExt: a tuple edge key names an unordered node pair | 7 7 0.0s test-mpdag.jl | 29 29 5.2s MPDAG: all-directed graph is valid (trivially Meek-closed) | 2 2 0.0s MPDAG: all-undirected chain is valid | 1 1 0.0s MPDAG: empty graph is valid | 2 2 0.2s MPDAG: rejects graph where Meek R1 would fire | 1 1 0.0s MPDAG: rejects directed cycle | 1 1 0.0s MPDAG: rejects non-directed/undirected edge types | 1 1 0.0s MPDAG <: AbstractPDAG | 2 2 0.0s is_mpdag: MPDAG instance returns true | 1 1 0.2s is_mpdag: CPDAG returns true (every CPDAG is an MPDAG) | 1 1 0.0s is_mpdag: PDAG where R1 would fire returns false | 1 1 0.1s is_mpdag: fully undirected PDAG is Meek-closed | 1 1 0.0s is_mpdag: DAG is always Meek-closed | 1 1 0.1s meek_closure returns MPDAG | 2 2 0.1s meek_closure MPDAG result is Meek-closed | 2 2 0.0s meek_closure: fully undirected input returns MPDAG | 1 1 0.0s MPDAG show: typename is MPDAG | 1 1 0.8s MPDAG: parents, children, neighbors work | 3 3 1.1s MPDAG: skeleton works | 2 2 0.6s MPDAG: dag_from_pdag works on MPDAG | 3 3 2.0s test-mutate.jl | 43 43 1.7s add_edges adds edge and preserves class | 3 3 0.1s add_edges adds multiple edges at once | 2 2 0.1s add_edges auto-adds new nodes from edge | 2 2 0.0s add_edges does not mutate original | 2 2 0.0s add_edges works on PDAG | 2 2 0.1s add_edges rejects invalid edge type for class | 1 1 0.0s add_edges on UNKNOWN allows duplicates | 2 2 0.1s remove_edges removes the correct edge | 2 2 0.3s remove_edges removes multiple edges at once | 2 2 0.1s remove_edges retains now-isolated nodes | 2 2 0.0s remove_edges throws on missing edge | 1 1 0.0s remove_edges does not mutate original | 1 1 0.0s add_nodes adds an isolated node | 2 2 0.1s add_nodes adds multiple isolated nodes | 3 3 0.1s add_nodes is idempotent for existing nodes | 1 1 0.0s add_nodes ignores already-present nodes in a mixed call | 1 1 0.0s remove_nodes removes node and incident edges | 2 2 0.2s remove_nodes removes multiple nodes and their incident edges | 2 2 0.2s remove_nodes removes only incident edges | 3 3 0.0s remove_nodes throws on missing node | 1 1 0.0s reclass changes graph class | 3 3 0.1s reclass throws on invalid edges for target class | 1 1 0.1s reclass to UNKNOWN allows duplicates afterward | 2 2 0.1s test-networklayout-ext.jl | 17 17 14.8s NetworkLayoutExt: every method returns one 2D position per node | 12 12 14.5s NetworkLayoutExt: :spring is reproducible with a seed | 1 1 0.2s NetworkLayoutExt: handles a graph with no edges | 1 1 0.1s NetworkLayoutExt: layout output feeds straight back into plot | 1 1 0.1s NetworkLayoutExt: default layout method becomes :stress once loaded | 2 2 0.0s test-operations.jl | 887 887 18.8s skeleton on DAG produces UG with same skeleton | 3 3 0.2s skeleton on PDAG produces UG with same skeleton | 3 3 0.2s subgraph on DAG returns DAG | 3 3 0.0s subgraph on CPDAG with v-structure: orphaned arrow downgrades to MPDAG | 5 5 0.2s subgraph on CPDAG: chordal undirected component stays MPDAG | 3 3 0.0s subgraph on MPDAG preserves MPDAG class | 1 1 0.0s subgraph on MAG stays a (maximal) MAG | 4 4 0.1s subgraph on MAG with bidirected edges stays a MAG | 3 3 0.0s subgraph on PAG downgrades to UNKNOWN | 4 4 0.0s subgraph on PAG: all-circle chain downgrades to UNKNOWN | 2 2 0.0s moralize works on DAGs | 10 10 0.6s NetworkX moralize test 1 | 6 6 0.0s latent_project basic confounding | 3 3 0.1s latent_project with no latents | 4 4 0.0s latent_project with multiple latents | 3 3 0.0s latent_project all nodes latent returns empty | 2 2 0.0s latent_project rejects unknown node name | 1 1 0.0s latent_project rejects non-DAG graph | 1 1 0.0s exogenize makes node exogenous, adds parent-to-child edges | 3 3 1.1s exogenize is idempotent for repeated nodes | 2 2 0.0s exogenize rejects unknown node | 1 1 0.0s exogenize multiple nodes | 3 3 0.0s dag_from_pdag converts a valid PDAG to a DAG | 4 4 1.6s dag_from_pdag errors on non-extendable PDAG | 1 1 0.0s dag_from_pdag preserves directed edges in mixed graph | 6 6 0.2s dag_from_pdag orients each undirected edge exactly once | 6 6 0.2s dag_from_pdag does not fabricate a v-structure | 3 3 0.1s meek_closure R1: orient compelled edge | 5 5 0.0s meek_closure R1 collider guard: do not create new unshielded collider | 3 3 0.0s meek_closure R2: orient along directed path | 3 3 0.0s meek_closure matches causal-learn regression | 8 8 0.0s normalize_latent_structure drops singleton latent | 2 2 2.7s normalize_latent_structure exogenizes then keeps latent with 2+ children | 4 4 0.0s normalize_latent_structure removes nested child set | 2 2 0.0s normalize_latent_structure rejects unknown latent | 1 1 0.0s normalize_latent_structure empty latent list returns same graph | 1 1 0.0s normalize_latent_structure preserves latent_project equivalence | 3 3 0.0s condition_marginalize: marginalize yields bidirected edge | 5 5 2.5s condition_marginalize: conditioning removes node, keeps structure | 3 3 0.1s condition_marginalize: Figure 11 conditioning on S | 7 7 0.2s condition_marginalize: Figure 11 marginalizing L1,L2 | 6 6 0.1s condition_marginalize: errors on empty cond/marg | 1 1 0.0s condition_marginalize: errors on overlapping cond/marg | 1 1 0.1s condition_marginalize: single remaining node returns empty AG | 2 2 0.0s condition_marginalize: accepts AG input | 2 2 1.1s condition_marginalize: accepts MAG input | 3 3 2.1s condition_marginalize: accepts ADMG input | 4 4 2.3s markov_equivalent: identical DAGs are equivalent | 1 1 0.0s markov_equivalent: reversed chain is equivalent | 1 1 0.0s markov_equivalent: fork equivalent to chain | 1 1 0.0s markov_equivalent: v-structure vs chain is not equivalent | 1 1 0.0s markov_equivalent: different skeletons are not equivalent | 1 1 0.0s markov_equivalent: different node sets are not equivalent | 1 1 0.0s markov_equivalent: single-node DAGs are equivalent | 1 1 0.1s markov_equivalent: shielded collider does not count as v-structure | 1 1 0.0s markov_equivalent: consistent with dag_to_cpdag | 625 625 0.7s markov_equivalent (MAG): identical MAGs are equivalent | 1 1 0.1s markov_equivalent (MAG): collider vs non-collider not equivalent | 1 1 0.0s markov_equivalent (MAG): different node sets not equivalent | 1 1 0.0s markov_equivalent (MAG): single-edge orientations are equivalent | 1 1 0.0s markov_equivalent (MAG): same collider via different edge marks | 1 1 0.0s markov_equivalent (MAG): all class members are mutually equivalent | 66 66 0.1s CausalEdge: symmetric edges are stored in canonical order | 15 15 1.1s cgraph: parallel edges are rejected | 12 12 0.5s test-pag-adjustment.jl | 28 28 3.5s is_valid_adjustment PAG: visible confounder blocks backdoor | 4 4 0.2s is_valid_adjustment PAG: invisible edge is not amenable | 3 3 0.0s is_valid_adjustment PAG: descendant of X is forbidden | 4 4 0.0s is_valid_adjustment PAG: all-circle triangle has no valid set | 3 3 0.1s all_adjustment_sets PAG: finds {A} for visible confounder | 1 1 1.8s all_adjustment_sets PAG: non-amenable graph returns no sets | 1 1 0.0s all_adjustment_sets PAG: consistent with is_valid_adjustment | 4 4 0.1s adjustment_set PAG: returns valid set, prefers smaller | 2 2 0.6s adjustment_set PAG: no valid set for non-amenable graph | 2 2 0.0s is_valid_adjustment/all_adjustment_sets/adjustment_set PAG: accepts Vector{Symbol} for x and y | 4 4 0.6s test-pag-separation.jl | 20 20 7.1s m_separated PAG: direct edge is never separated | 1 1 4.8s m_separated PAG: chain with confounder | 5 5 0.1s m_separated PAG: collider blocks without conditioning | 4 4 0.1s m_separated PAG: conditioning on x returns true | 1 1 0.0s minimal_separator PAG: chain returns middle node | 1 1 1.2s minimal_separator PAG: direct edge returns nothing | 1 1 0.0s minimal_separator PAG: two paths require both confounders | 1 1 0.0s minimal_separator PAG: restrict excludes required node | 1 1 0.4s minimal_separator PAG: result is a valid separator | 3 3 0.0s minimal_separator PAG: accepts Vector{Symbol} for x and y | 2 2 0.5s test-pag-to-mag.jl | 35 35 0.7s mag_from_pag: returns a MAG with the PAG's skeleton | 3 3 0.3s mag_from_pag: o-> becomes --> (docstring) | 2 2 0.1s mag_from_pag: invariant arrowheads and tails are kept | 3 3 0.0s mag_from_pag: invariant bidirected edge is kept (R4 collider) | 2 2 0.0s mag_from_pag: round-trips on a collider PAG | 1 1 0.0s mag_from_pag: round-trips on an all-circle chain PAG | 2 2 0.0s mag_from_pag: round-trips with a discriminating path (R4) | 2 2 0.0s mag_from_pag: round-trips on a bidirected-only PAG | 2 2 0.0s mag_from_pag: circle chain avoids a new collider | 3 3 0.0s mag_from_pag: shielded circle triangle stays acyclic | 3 3 0.0s cgraph rejects a shielded triangle marked with all arrowheads as a PAG | 2 2 0.0s mag_from_pag: is deterministic | 1 1 0.0s mag_from_pag: o-- becomes a directed edge (docstring) | 3 3 0.1s mag_from_pag: keeps undirected (---) edges and round-trips | 3 3 0.0s mag_from_pag: round-trips a PAG with an o-- edge | 3 3 0.1s test-pagcauses.jl | 19 19 12.2s pagcauses: X not a possible ancestor of Y returns no causal effect | 1 1 9.3s pagcauses: identifiable directly returns the single backdoor set (Proposition 1) | 1 1 0.0s pagcauses matches Fig. 2 of Wang, Tao, Qin & Zhou (2025) end to end | 1 1 0.1s pagcauses matches brute-force MAG enumeration (Theorem 4) when unidentifiable | 4 4 1.7s pagcauses: every returned set is sound (a real Definition 1 adjustment set) | 10 10 0.8s pagcauses: W-bar is computed on M_X, excluding X's directed-out neighbors | 1 1 0.2s pagcauses: rejects graphs with undirected (selection-variable) edges | 1 1 0.0s test-pdag-adjustment.jl | 46 46 7.4s is_valid_adjustment AbstractPDAG: classic confounder (all directed) | 3 3 0.2s is_valid_adjustment AbstractPDAG: chain has valid empty set | 1 1 0.0s is_valid_adjustment AbstractPDAG: rejects descendant of X | 2 2 0.2s is_valid_adjustment AbstractPDAG: undirected edge forbids possible descendant | 2 2 0.0s is_valid_adjustment AbstractPDAG: undirected confounder | 2 2 0.0s is_valid_adjustment AbstractPDAG: MPDAG: basic confounder | 2 2 0.0s all_adjustment_sets AbstractPDAG: finds {A} for classic confounder | 1 1 1.6s all_adjustment_sets AbstractPDAG: chain returns empty set | 2 2 0.0s all_adjustment_sets AbstractPDAG: undirected forbids all candidates | 2 2 0.1s all_adjustment_sets AbstractPDAG: consistent with is_valid_adjustment | 2 2 0.1s all_adjustment_sets AbstractPDAG: no valid set when all candidates forbidden | 1 1 0.0s d_separated AbstractPDAG: chain is open | 2 2 1.1s d_separated AbstractPDAG: all-directed DAG-as-CPDAG agrees with DAG result | 2 2 0.0s d_separated AbstractPDAG: ambiguous undirected chain | 2 2 0.3s d_separated AbstractPDAG: definite collider blocks | 2 2 0.0s d_separated AbstractPDAG: conditioning on x returns true | 1 1 0.2s adjustment_set AbstractPDAG: optimal returns {A} for classic confounder | 2 2 0.7s adjustment_set AbstractPDAG: parents type returns directed parents of x | 1 1 0.7s adjustment_set AbstractPDAG: optimal on chain returns empty | 1 1 0.1s adjustment_set AbstractPDAG: optimal result is always valid | 1 1 0.0s minimal_separator AbstractPDAG: directed chain returns middle node | 1 1 0.9s minimal_separator AbstractPDAG: undirected chain returns middle node | 1 1 0.3s minimal_separator AbstractPDAG: v-structure already d-separated | 1 1 0.0s minimal_separator AbstractPDAG: direct edge returns nothing | 1 1 0.0s minimal_separator AbstractPDAG: accepts Vector{Symbol} for x and y | 2 2 0.5s is_valid_adjustment/all_adjustment_sets AbstractPDAG: accepts Vector{Symbol} for x and y | 3 3 0.2s is_valid_adjustment MPDAG: empty set is invalid when background knowledge introduces a partially directed cycle | 3 3 0.2s test-possible-adjustment-sets.jl | 19 19 4.9s possible_optimal_adjustment_sets matches the worked example (Maathuis, Kalisch & Bühlmann 2009, Fig. 2) | 5 5 3.3s possible_optimal_adjustment_sets: O-set can be a strict subset of the parent set | 3 3 0.3s possible_optimal_adjustment_sets: nothing when y is a parent of x for that orientation | 3 3 0.0s possible_optimal_adjustment_sets: single valid orientation when x has no undirected neighbors | 2 2 0.2s possible_optimal_adjustment_sets: agrees with adjustment_set(:optimal) on the oriented MPDAG | 4 4 0.5s possible_optimal_adjustment_sets works on MPDAG | 2 2 0.5s test-possible-d-sep.jl | 6 6 0.4s possible_d_sep matches the worked backdoor_set(::MAG) example, before M_X removes the visible edge | 2 2 0.3s possible_d_sep accepts a set of target nodes | 1 1 0.1s possible_d_sep works on AG | 1 1 0.1s possible_d_sep excludes x itself and returns nothing when x has no collider paths | 2 2 0.0s test-possible-joint-parent-sets.jl | 28 28 3.6s possible_joint_parent_sets rejects duplicate or empty xs | 2 2 1.5s possible_joint_parent_sets reduces to possible_parent_sets for a singleton | 4 4 0.2s possible_joint_parent_sets: worked example with two intervention nodes | 1 1 1.6s possible_joint_parent_sets rejects a new v-structure away from xs | 4 4 0.1s possible_joint_parent_sets rejects orientations that would create a cycle | 13 13 0.2s possible_joint_parent_sets: entries are ordered like xs and pairwise consistent | 4 4 0.1s test-print.jl | 8 8 1.6s print: directed edge (-->) | 1 1 0.4s print: undirected edge (---) | 1 1 0.4s print: bidirected edge (<->) | 1 1 0.4s print: partially_directed edge (o->) | 1 1 0.4s print: partially_undirected edge (o--) | 1 1 0.0s print: partial edge (o-o) | 1 1 0.0s print: no edges | 1 1 0.0s print: singular node/edge labels | 1 1 0.0s test-queries.jl | 218 218 11.4s is_acyclic returns true for DAG/PDAG by class | 1 1 0.0s is_acyclic detects cycles in UNKNOWN graphs | 1 1 0.1s is_simple reflects graph content | 2 2 0.0s is_dag works | 4 4 0.1s is_pdag works | 3 3 0.0s is_ug works | 4 4 0.2s is_admg works | 3 3 0.0s parents returns expected nodes | 2 2 1.1s children returns expected nodes | 3 3 0.0s neighbors returns adjacency (directed + undirected) | 2 2 0.0s parents/children match by node name | 3 3 0.0s parents/children are not defined for UG | 2 2 0.0s neighbors for UG returns undirected adjacency | 4 4 0.0s ancestors works on DAG | 3 3 0.0s descendants works on DAG | 3 3 0.5s ancestors/descendants open vs closed definition | 3 3 0.0s ancestors errors on UG | 1 1 0.0s descendants errors on UG | 1 1 0.0s ancestors NetworkX 1 test | 3 3 0.0s descendants NetworkX 1 test | 3 3 0.0s markov_blanket works on DAGs (parents, children, spouses) | 2 2 0.5s markov_blanket includes undirected neighbors in PDAGs | 1 1 0.6s markov_blanket multi-parent fixture on DAGs | 2 2 0.0s markov_blanket errors on UG | 1 1 0.0s exogenous_nodes works on DAG | 1 1 0.3s exogenous_nodes works on PDAG | 1 1 0.1s exogenous_nodes works on UG | 2 2 0.3s possible_ancestors on CPDAG: undirected chain | 4 4 0.8s possible_ancestors on CPDAG: compelled v-structure | 3 3 0.0s possible_ancestors on CPDAG: mixed directed and undirected | 2 2 0.0s possible_ancestors open/closed definition | 2 2 0.0s possible_descendants on CPDAG: undirected chain | 4 4 0.7s possible_descendants on CPDAG: compelled v-structure | 2 2 0.0s possible_descendants open/closed definition | 2 2 0.0s possible_ancestors/descendants are supersets of ancestors/descendants | 12 12 0.2s possible_ancestors/descendants on MPDAG: partially directed cycles are unsound to ignore | 4 4 0.2s possible_ancestors/descendants on CPDAG are unaffected by the MPDAG fix | 8 8 0.2s possible_parent_sets matches the worked example (Maathuis, Kalisch & Bühlmann 2009, Fig. 2) | 2 2 0.0s possible_parent_sets returns a single set when x has no undirected neighbors | 2 2 0.0s possible_parent_sets excludes subsets that create a new v-structure | 2 2 0.0s possible_parent_sets: sets agree with parents over the DAGs in the equivalence class (Theorem 3.2) | 6 6 0.1s possible_ancestors on PAG: unshielded collider (o-> edges) | 3 3 0.0s possible_descendants on PAG: unshielded collider (o-> edges) | 3 3 0.0s possible_ancestors on PAG: all-circle chain (o-o edges) | 3 3 0.0s possible_descendants on PAG: all-circle chain (o-o edges) | 2 2 0.0s possible_ancestors on PAG: R1-propagated tail (invariant directed edge) | 2 2 0.0s possible_descendants on PAG: R1-propagated tail | 2 2 0.0s possible_ancestors on PAG: open/closed kwarg | 2 2 0.0s anteriors works for DAG (equals ancestors) | 3 3 0.0s anteriors works for ADMG (equals ancestors) | 3 3 0.0s anteriors works for PDAG with mixed edges | 4 4 0.7s anteriors works for PDAG with undirected cycle | 3 3 0.0s anteriors errors on UG | 1 1 0.0s posteriors works for DAG (equals descendants) | 3 3 0.0s posteriors works for ADMG (equals descendants) | 3 3 0.0s posteriors works for PDAG with mixed edges | 4 4 0.9s posteriors works for PDAG with undirected cycle | 3 3 0.0s posteriors errors on UG | 1 1 0.0s posteriors excludes the node itself | 1 1 0.0s posteriors does not return duplicates in undirected cycles | 1 1 0.1s posteriors handles multi-step mixed reachability | 1 1 0.0s posteriors handles disconnected components | 2 2 0.0s closed definition for ancestors/anteriors/descendants/posteriors | 8 8 0.8s subgraph on DAG | 4 4 0.0s subgraph on UG | 3 3 0.0s subgraph on PDAG | 3 3 0.1s spouses works for ADMG | 1 1 0.0s districts works for ADMG | 1 1 0.0s districts works for AG | 1 1 0.5s districts works for MAG | 2 2 0.2s is_cpdag: CPDAG class is always true | 1 1 0.0s is_cpdag: PDAG v-structure is a valid CPDAG | 1 1 0.0s is_cpdag: PDAG single directed edge is not a CPDAG | 1 1 0.0s is_cpdag: pure directed chain is not a CPDAG | 1 1 0.0s is_cpdag: undirected edge is a valid CPDAG | 1 1 0.0s is_cpdag: undirected chain is a valid CPDAG | 1 1 0.0s is_cpdag: undirected triangle is a valid CPDAG | 1 1 0.0s is_cpdag: triangle with adjacent parents is not a CPDAG | 1 1 0.0s is_cpdag: isolated nodes are a valid CPDAG | 1 1 0.0s is_cpdag: v-structure + isolated nodes is a valid CPDAG | 1 1 0.0s is_cpdag: non-chordal 4-cycle is not a CPDAG | 1 1 0.0s is_cpdag: rejects Meek R1 violation | 1 1 0.0s is_cpdag: rejects Meek R2 violation | 1 1 0.0s is_cpdag: rejects Meek R3 violation | 1 1 0.0s is_cpdag: rejects Meek R4 violation | 1 1 0.0s is_cpdag: complex valid CPDAG with v-structure + undirected components | 1 1 0.0s is_cpdag: v-structure with R1 cascade (C-->E<--B, E-->F) is valid | 1 1 0.0s is_cpdag: PDAG with B-->A and B-->C (fork) is not a CPDAG | 1 1 0.0s is_cpdag: CPDAG constructor rejects invalid graph | 1 1 0.0s is_cpdag: generate_graph(CPDAG) produces valid CPDAGs | 10 10 1.3s test-separation.jl | 42 42 4.2s d_separated: chain structure | 2 2 0.0s d_separated: fork structure | 2 2 0.0s d_separated: collider structure | 2 2 0.0s d_separated: naive Bayes conditional independence pattern | 3 3 0.0s d_separated: Asia-style fixture | 2 2 0.0s minimal_separator: chain structure | 1 1 1.2s minimal_separator: fork structure | 1 1 0.0s minimal_separator: collider returns empty separator | 1 1 0.0s minimal_separator: returns nothing when no separator exists | 1 1 0.0s minimal_separator: default R excludes X and Y | 1 1 0.0s NetworkX Case 1: large_collider_graph | 2 2 0.0s NetworkX Case 2: chain_and_fork_graph | 2 2 0.0s NetworkX Case 3: no_separating_set_graph | 2 2 0.0s NetworkX Case 4: large_no_separating_set_graph | 2 2 0.0s paper Fig 4 G1: minimal_separator returns {V2} | 1 1 0.0s m_separated: chain in ADMG | 2 2 0.0s m_separated: bidirected confounding | 1 1 0.0s minimal_separator on ADMG | 1 1 0.5s minimal_separator returns nothing for unblockable bidirected | 1 1 0.0s d_separated: accepts Vector{Symbol} for x and y | 3 3 0.2s d_separated: set result matches pairwise conjunction | 1 1 0.5s d_separated: empty vector is trivially separated | 2 2 0.1s m_separated: accepts Vector{Symbol} for x and y (ADMG) | 2 2 0.4s minimal_separator: accepts Vector{Symbol} for x and y (DAG) | 2 2 1.0s minimal_separator: accepts Vector{Symbol} for x and y (ADMG) | 2 2 0.3s test-sim.jl | 760 760 7.3s sim: adjustment_set :backdoor is always valid on random DAGs | 25 25 0.9s sim: adjustment_set :parents is always valid on random DAGs | 25 25 0.2s sim: all_backdoor_sets - every returned set is valid | 69 69 0.3s sim: all_backdoor_sets minimal=true - no proper subset is also in the list | 0 0.3s sim: topological sort - every parent precedes its child | 232 232 0.1s sim: ancestors/descendants are mutual in random DAGs | 270 270 0.5s sim: Markov blanket separates node from non-blanket nodes | 124 124 0.6s sim: fork - marginal dependence, conditional independence given common cause | 4 4 3.9s sim: chain - marginal dependence, conditional independence given mediator | 4 4 0.1s sim: collider - marginal independence, activation by conditioning on collider | 4 4 0.0s sim: adjustment set removes confounding in regression | 3 3 0.3s test-simulation.jl | 177 177 5.8s generate_graph: errors on invalid n | 1 1 0.5s generate_graph: errors on invalid p | 2 2 0.4s generate_graph: errors on invalid m | 2 2 0.0s generate_graph: errors when neither m nor p supplied | 1 1 0.0s generate_graph: errors when both m and p supplied | 1 1 0.1s generate_graph: DAG with m=0 yields 0 edges and correct nodes | 4 4 0.2s generate_graph: DAG with p=0 yields 0 edges | 1 1 0.1s generate_graph: m=tot yields full tournament DAG | 2 2 0.2s generate_graph: reproducible with same seed | 2 2 0.0s generate_graph: CPDAG class returns CPDAG | 2 2 0.1s generate_graph: unsupported class gives TypeError | 1 1 0.0s generate_graph: ADMG class returns ADMG over exactly n observed nodes | 2 2 0.2s generate_graph: MAG class returns a valid MAG over exactly n observed nodes | 60 60 0.6s generate_graph: PAG class returns a valid PAG over exactly n observed nodes | 60 60 0.3s generate_graph: PAG and MAG agree given the same seed | 1 1 0.0s generate_graph: ADMG/MAG with latents=0 has no bidirected edges | 1 1 0.1s generate_graph: latents keyword rejected for DAG/CPDAG classes | 2 2 0.0s generate_graph: latents must be non-negative | 1 1 0.0s simulate_data: errors on non-DAG graph class | 2 2 0.0s simulate_data: errors on empty graph | 1 1 1.6s simulate_data: errors on invalid samples | 2 2 0.0s simulate_data: returns dict with correct keys | 2 2 0.1s simulate_data: correct number of samples | 1 1 0.2s simulate_data: reproducible with seed | 3 3 0.1s simulate_data: different seeds produce different data | 1 1 0.1s simulate_data: standardize=true yields mean≈0 and sd≈1 | 6 6 0.3s simulate_data: standardize=false does not standardize | 1 1 0.3s simulate_data: endogenous nodes correlate with parents | 1 1 0.0s simulate_data: single node graph works | 2 2 0.1s simulate_data: graph with no edges (all exogenous) | 4 4 0.1s simulate_data: deep chain graph | 2 2 0.2s simulate_data: collider structure A and B independent | 3 3 0.0s test-topological-sort.jl | 24 24 0.7s topological_sort on simple chain DAG | 3 3 0.3s topological_sort on diamond DAG | 3 3 0.1s topological_sort with isolated nodes | 3 3 0.1s topological_sort on empty DAG (only nodes, no edges) | 2 2 0.0s topological_sort on single node DAG | 1 1 0.0s topological_sort errors on ADMG | 1 1 0.0s topological_sort errors on PDAG | 1 1 0.0s topological_sort errors on UG | 1 1 0.0s topological_sort returns all nodes exactly once | 3 3 0.1s topological_sort NetworkX 1 test | 4 4 0.1s topological_sort NetworkX 2 test | 2 2 0.1s test-uniform-dag.jl | 50026 50026 7.4s uniform_dag: errors on invalid n | 2 2 1.2s uniform_dag: n=1 yields a single node and no edges | 3 3 0.6s uniform_dag: returns a valid DAG with correct nodes | 4 4 0.1s uniform_dag: reproducible with same seed | 1 1 0.2s uniform_dag: DAG counts match A003024 (labelled DAGs by n) | 1 1 0.4s uniform_dag: outpoint counts for n=5 match Kuipers & Moffa Table 1 | 1 1 0.0s uniform_dag: reproduces the Kuipers & Moffa worked example | 1 1 0.0s uniform_dag: outpoint sequences always sum to n | 10 10 0.6s uniform_dag: exhaustive uniformity check against brute force (n=3) | 50003 50003 4.5s Testing CausalStructures tests passed Testing completed after 758.92s PkgEval succeeded after 903.95s