Skip to content

Broadcasting into ComponentArray fields fails with AssertionError: x.indices == dx.indices #2921

@ChrisRackauckas-Claude

Description

@ChrisRackauckas-Claude

Summary

Broadcasting into ComponentArray fields fails with Enzyme. Explicit loops work fine, but broadcast syntax (.=) fails.

Environment

  • Julia version: 1.12.4
  • Enzyme version: 0.13.118
  • ComponentArrays version: 0.15.31

Minimal Reproducible Example

using Enzyme
using ComponentArrays

u = ComponentArray(a = [1.0, 2.0])
p = ComponentArray(p = 2.0)

# ✓ WORKS: Using explicit loop
function f_loop!(du, u, p)
    for i in eachindex(du.a)
        du.a[i] = u.a[i] * p.p
    end
    return nothing
end

du1 = similar(u)
du1_shadow = ComponentArray(a = ones(2))
dp1_shadow = ComponentArray(p = 0.0)
f_loop!(du1, u, p)

Enzyme.autodiff(
    Enzyme.Reverse,
    f_loop!,
    Const,
    Duplicated(du1, du1_shadow),
    Const(u),
    Duplicated(p, dp1_shadow)
)
println("Loop version works: dp_shadow = ", dp1_shadow)  # (p = 3.0) ✓

# ✗ FAILS: Using broadcast
function f_broadcast!(du, u, p)
    du.a .= u.a .* p.p  # This line causes the issue
    return nothing
end

du2 = similar(u)
du2_shadow = ComponentArray(a = ones(2))
dp2_shadow = ComponentArray(p = 0.0)
f_broadcast!(du2, u, p)

# Without runtime activity: EnzymeRuntimeActivityError
Enzyme.autodiff(
    Enzyme.Reverse,
    f_broadcast!,
    Const,
    Duplicated(du2, du2_shadow),
    Const(u),
    Duplicated(p, dp2_shadow)
)

Errors

Without runtime activity:

EnzymeRuntimeActivityError: Detected potential need for runtime activity.

With runtime activity (set_runtime_activity(Reverse)):

AssertionError: x.indices == dx.indices

The assertion failure occurs in EnzymeCore.jl at the Duplicated constructor.

Analysis

The issue appears to be:

  1. ComponentArray field access (du.a) returns a SubArray view into the underlying data
  2. When Enzyme creates shadow arrays for the broadcast operation with runtime activity mode, it creates a Duplicated(primal_subarray, shadow_subarray) pair
  3. The primal and shadow SubArrays have different internal indices fields (even though they have the same shape), triggering the assertion failure

Impact

This affects SciML users trying to use EnzymeVJP with ComponentArrays for ODE sensitivity analysis. See: SciML/SciMLSensitivity.jl#1287

Workaround

Users can work around this by using explicit loops instead of broadcasting, or by using a different AD backend (Zygote, ReverseDiff).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions