Compiled DAG propagation: ~3x speedup over persistent DAG#226
Open
dpsanders wants to merge 9 commits into
Open
Compiled DAG propagation: ~3x speedup over persistent DAG#226dpsanders wants to merge 9 commits into
dpsanders wants to merge 9 commits into
Conversation
…ompatibility Update compat bounds: IntervalArithmetic 1, IntervalBoxes 0.3, IntervalContractors 0.6, ReversePropagation 0.4, Symbolics 7. IntervalArithmetic v1.0 follows IEEE 1788 and deliberately does not define Base.isequal/Base.hash for Interval. This broke @register_symbolic x ∈ y::Interval since SymbolicUtils needs isequal/hash for hash-consing. Instead of type-pirating those methods, decompose x ∈ interval(a,b) into (x >= a) & (x <= b) at the symbolic level. Also fix pre-existing bug in separator() where & and | used Base.intersect/union instead of ⊓/⊔ (defined for AbstractSeparator in set_operations.jl). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cherry-pick infrastructure changes from PR #220: - Update GitHub Actions versions (checkout v6, setup-julia v2, cache v3, codecov v6) - Test on Julia 1.11 instead of 1.10 - Set julia compat to 1.11 - Remove obsolete REQUIRE file (Pkg.jl era) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Switch from the old Documenter HTML backend to DocumenterVitepress for a modern VitePress-based documentation site. Add new pages explaining contractors/separators and the internal architecture, update index.md to the current API, add GitHub Actions workflow for doc deployment, and remove stale mkdocs.yml and Manifest.toml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements an explicit DAG (directed acyclic graph) for forward-backward
interval constraint propagation (HC4Revise), inspired by Schichl & Neumaier.
This provides an inspectable, iterable alternative to the existing
ReversePropagation code-generation approach.
New types: DAGContractor, DAGSeparator, ConstraintDAG
New files: src/dag/{nodes,build,propagate,contractor}.jl
Tests: test/test_dag.jl (27 tests)
Benchmarks: benchmark/bench_dag_vs_codegen.jl
Both approaches produce identical paving results. The DAG approach is
currently ~10x slower due to DAG reconstruction per call and dynamic
dispatch, with clear optimization paths documented in CLAUDE.md.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Redesign the DAG engine so the graph is built once and reused: - SharedDAG: persistent DAG that accumulates constraints via add_expression!. Variable nodes and common subexpressions (CSE) are shared across all expressions added to the same DAG. - Multi-constraint propagation: forward-backward passes contract all constraints jointly, so narrowing from one constraint immediately benefits others through shared variable nodes. - DAGContractor/DAGSeparator accept an existing SharedDAG, allowing multiple separators to share the same graph. Benchmarks show ~30% speedup vs the previous rebuild-per-call approach, and shared DAGs use 33% fewer nodes than separate ones. Resolves Project.toml merge conflict from cherry-pick. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Compile the SharedDAG into a flat instruction array (CompiledDAG) that operates on a pre-allocated workspace of intervals, combining three optimizations: 1. Symbol-keyed operations instead of Function dispatch 2. Pre-allocated flat workspace indexed by slot number 3. Flat instruction array — forward iterates forward, backward reverses Benchmarks show ~3x speedup over the uncompiled persistent DAG, bringing the gap with code-generation down from ~8x to ~3x while retaining full inspectability and multi-constraint support. | Problem | Codegen | Compiled DAG | Ratio | |-----------------|---------|-------------|-------| | Unit disk ϵ=0.1 | 294 μs | 1.0 ms | 3.5x | | Annulus ϵ=0.1 | 1.6 ms | 4.4 ms | 2.8x | | 3D torus ϵ=1.0 | 12 ms | 33 ms | 2.8x | Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Builds on the persistent shared DAG (#225) by compiling the
SharedDAGinto a flatCompiledDAGinstruction schedule, combining three optimizations:op::Symbol(:add,:mul, etc.) instead ofop::Function, enabling fast===comparison without dynamic dispatchVector{Interval}indexed by slot number; no per-node allocation during traversalVector{Instruction}in topological order; forward iterates forward, backward iterates in reverseBenchmarks
The compiled DAG is now within ~3x of the code-generation approach (down from ~8x), while retaining full DAG inspectability, multi-constraint support, and no
eval().How it works
compile(dag::SharedDAG)walks the DAG and:Vector{Interval}workspaceOperationNodeinto anInstruction(op::Symbol, out, arg1, arg2)DAGContractorandDAGSeparatornow store aCompiledDAGand use it for propagation automatically.Test plan
🤖 Generated with Claude Code