feat(ad): linear-operator pullback rules (DESIGN §6) — re-verify against current Enzyme
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 35/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bastante claro
- Estado de actividad
- Tranquilo
- Stack tecnológico
- julia
- Área
- backend, performance, testing-qa
Línea de trabajo
Start with DESIGN.md §6 and test/autodiff.jl, then rerun the mixed pointer/isbits rule-argument MWE using Enzyme at least 0.13.202 under Julia 1.12. Done means establishing whether the calling-convention blocker remains; if it does, document the result against EnzymeAD/Enzyme.jl#3322 before revisiting the rule implementation.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Status update 2026-09-30. This is a performance item, not a correctness one: gradients are already exact via the tape (see below). The upstream blocker still needs re-verification. The tracker named below, EnzymeAD/Enzyme.jl#2707, was closed as completed on 2026-02-01, before this issue was filed. No Manifest is committed any more; the test suite is currently on Enzyme 0.13.204 (the version cited in the 1.13 skip comments at
test/autodiff.jl:89,198andtest/enzyme_rules.jl:133), and the current release is 0.13.208. CI now runs Julia 1.10 and 1.13 only (1.12 dropped in d989b79), so the 1.12CallingConventionMismatchErrorbelow is never exercised in CI. So "blocked" is unverified: re-run the mixed pointer/isbits rule-argument MWE on current Enzyme under Julia 1.12 and 1.13 before treating this as blocked. If it still fails, EnzymeAD/Enzyme.jl#3322 (CallingConventionMismatchErrorinclassify_argumentsfor a mixed pointer/isbits struct, still open; its title scopes it to nested differentiation on Julia ≤ 1.11) is the closest live upstream issue to point at instead. Scope is Enzyme only: the Mooncakerrule!!half of §6 is out, since Mooncake rule parity (#44) was closed as not planned; Mooncake stays a test-time CPU cross-check.
DESIGN.md §6 specifies custom rules that route the reverse-mode pullback of a linear operator through its already-declared apply_adjoint!, instead of taping the leaf bodies. That is still the right design, and it is still unbuilt — ext/MatrixFreeOperatorsEnzymeCoreExt.jl registers rules only for the _exchange_storage!/_bc_storage! seams and their transposes — but the blocker turned out to be upstream, not us.
Why it is blocked
From Julia 1.12, an Enzyme custom-rule argument may not have a type that mixes GC-tracked pointers with inline floats. It is a hard error:
CallingConventionMismatchError: ... has mismatch between roots_activep (DFT_DUP_ARG) and activep (DFT_CONSTANT).
- Non-rooted types: (Int64, ..., Float64, Float64, ...)
- Rooted types: (Vector{Matrix{Float64}}, ..., Base.RefValue{...})
Hint: You are currently on Julia 1.12, which changed its calling convention.
Tracking issue: https://github.com/EnzymeAD/Enzyme.jl/issues/2707
Field, BlockField, PackedBlockField and BlockForest all qualify, through the grid they embed. That disqualifies every seam the §6 plan named:
| Intended seam | Blocked because |
|---|---|
apply(L, x) |
takes and returns a Field — cannot be worked around by re-parameterising arguments |
apply!(y, L, x, g, α, β) |
Field arguments |
mul!(y, ::PreparedOperator, x, α, β) |
PreparedOperator argument |
_forest_sweep! / _forest_adjoint_sweep! |
AbstractBlockField arguments |
The halo/BC sweeps were reachable only because they could be re-cut against raw storage (_exchange_storage! / _bc_storage! over a block vector or packed array plus isbits descriptors) — see _storage/_layout/BlockLayout. apply cannot be re-cut that way while it returns a field.
What we lose meanwhile
Not correctness — the tape still produces the right gradients, verified against the declared adjoint throughout test/autodiff.jl (at rtol=1e-10 on single grids, 1e-8 on forests). What we lose is the efficiency win of skipping the leaf tape entirely, and the structural guarantee for @kernel-authored leaves that §6 calls mandatory (the exchange sweeps now have it; the operator sweeps do not).
When to revisit
Once the MWE above passes on current Enzyme (i.e. once Enzyme.jl#2707's fix is confirmed to cover this case). The scoping work is already done and should be reused:
- gate on operator type, one rule per parameter-free linear leaf (
Laplacian,Derivative,Gradient,Divergence,IdentityOp,Restriction,Prolongation) — a rule cannot decline and fall back to taping, so a trait branch inside the rule body is not an option; - deliberately exclude
ScalingOpandAdvection{_,<:AbstractField}, whose coefficient fields are differentiable parameters — a rule firing there would silently zerodκ(test/autodiff.jlguards this, but itsScalingOpκ testset is skipped on Julia 1.13, so in CI only the 1.10 job runs it until #108 re-enables it); - accumulate with
apply_adjoint!(x̄, L, ȳ, g, α, true), and keep ghost cotangents exactly zero; - rule bodies must not allocate (see #40).
—
🤖 Claude brought this status note forward from the Julia 1.12 era.
claude-opus-5-5[1m] (high) · claude-code 2.1.285 · unreviewed
- Lenguaje dominante
- Julia
- Estrellas
- 3
- Forks
- 1
- Merge medio
- 1 d 28 min
- PR fusionados (30 d)
- 6
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de RallypointOne/MatrixFreeOperators.jl
-
Roadmap: open-issue priorityAbierto
Dificultad 4/5 3-5 días Aptitud para principiantes 45/100
-
enhancement
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
-
performance
Dificultad 5/5 Más de una semana Aptitud para principiantes 45/100
-
perf(forest): thread the reference BlockForest path — leaf sweeps and exchange descriptor loopsAbiertoperformance
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
-
enhancement
Dificultad 5/5 Más de una semana Aptitud para principiantes 25/100
Todos los issues de RallypointOne/MatrixFreeOperators.jl
Issues similares
-
io
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
JuliaGPU/GPUArrays.jl#837 ·
Los mantenedores suelen responder en 2 días
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 68/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
bmad-sim/BeamTracking.jl#382 ·
Los mantenedores suelen responder en 1 día