Skip to content

Commit ecefef4

Browse files
SebastianM-Cclaude
andcommitted
refactor: add static indexing for discrete/constants/nonnumeric
This adds StaticBufferIndex to perform indexing in the type domain for the discrete/constants/nonnumeric portions. This mainly helps Enzyme's type analysis for use cases that include nonnumeric parameters, like neural networks. See SciML/SciMLSensitivity.jl#1477 for more details. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 6d0dd38 commit ecefef4

1 file changed

Lines changed: 39 additions & 0 deletions

File tree

lib/ModelingToolkitBase/src/systems/problem_utils.jl

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,12 @@ function __apply_copy_template(valp, template)
772772
return p.constant[template.idx[1]][template.idx[2]]
773773
elseif template isa ParameterIndex{Nonnumeric, Tuple{Int, UnitRange{Int}}}
774774
return p.nonnumeric[template.idx[1]][template.idx[2]]
775+
elseif template isa StaticBufferIndex{SciMLStructures.Discrete}
776+
return _static_buffer(p.discrete, template)[template.range]
777+
elseif template isa StaticBufferIndex{SciMLStructures.Constants}
778+
return _static_buffer(p.constant, template)[template.range]
779+
elseif template isa StaticBufferIndex{Nonnumeric}
780+
return _static_buffer(p.nonnumeric, template)[template.range]
775781
elseif template isa UnitRange{Int}
776782
return u[template]
777783
elseif template isa ObservedWrapper
@@ -801,6 +807,27 @@ end
801807
struct IndepVarTemplate end
802808
const IV_TEMPLATE = IndepVarTemplate()
803809

810+
"""
811+
$TYPEDEF
812+
813+
Template entry for `CopyParamsByTemplate` indexing into one of the inner buffers of a
814+
multi-buffer `MTKParameters` portion (discrete/constants/nonnumeric). Unlike
815+
`ParameterIndex{P, Tuple{Int, UnitRange{Int}}}`, the buffer index `I` is lifted into the
816+
type domain so that indexing the heterogeneously-typed tuple of buffers constant-folds and
817+
infers concretely. With a runtime buffer index the result is a small `Union` of the buffer
818+
types, which Enzyme's type analysis rejects (`IllegalTypeAnalysisException`) when it flows
819+
into `reshape` inside the `CopyParamsByTemplate` compile unit.
820+
"""
821+
struct StaticBufferIndex{P, I}
822+
range::UnitRange{Int}
823+
end
824+
825+
function StaticBufferIndex{P}(idx::Tuple{Int, UnitRange{Int}}) where {P}
826+
return StaticBufferIndex{P, idx[1]}(idx[2])
827+
end
828+
829+
@inline _static_buffer(bufs::Tuple, ::StaticBufferIndex{P, I}) where {P, I} = bufs[I]
830+
804831
Base.@nospecializeinfer function __specialize_templates(template::Vector{Any}, elem_types::Set{DataType})
805832
if length(template) <= 4
806833
return Tuple(template)
@@ -913,6 +940,18 @@ function CopyParamsByTemplate(srcsys::AbstractSystem, syms::AbstractArray{Symbol
913940
end
914941
end
915942

943+
# Lift buffer indices of multi-buffer portions (discrete/constants/nonnumeric) into
944+
# the type domain. This is done as a final pass so the contiguous-range merging above
945+
# can keep operating on plain `ParameterIndex`es.
946+
for i in eachindex(template)
947+
entry = template[i]
948+
if entry isa ParameterIndex && entry.idx isa Tuple{Int, UnitRange{Int}}
949+
delete!(elem_types, typeof(entry))
950+
template[i] = StaticBufferIndex{typeof(entry.portion)}(entry.idx)
951+
push!(elem_types, typeof(template[i]))
952+
end
953+
end
954+
916955
return CopyParamsByTemplate{true}(__specialize_templates(template, elem_types), size(syms))
917956
end
918957

0 commit comments

Comments
 (0)