Skip to content

Commit 10611b6

Browse files
Merge pull request #4678 from SciML/as/fix-ci
fix: fix bugs, improve type-stability
2 parents 7115f69 + 5b34204 commit 10611b6

5 files changed

Lines changed: 58 additions & 9 deletions

File tree

lib/ModelingToolkitBase/src/problems/nonlinearproblem.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ function generate_nonlinear_bounds(sys::AbstractSystem, op)
9090
left_merge!(lbmap, op)
9191
lb = varmap_to_vars(lbmap, dvs; tofloat = false)
9292
ubmap = SymmapT()
93-
for (var, b) in zip(dvs, lb)
94-
b === -Inf && continue
93+
for (var, b) in zip(dvs, ub)
94+
b === Inf && continue
9595
write_possibly_indexed_array!(ubmap, var, Symbolics.SConst(b), COMMON_NOTHING)
9696
end
9797
left_merge!(ubmap, op)

lib/ModelingToolkitBase/src/systems/index_cache.jl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -644,14 +644,20 @@ function reorder_parameters(ic::IndexCache, ps::Vector{SymbolicT}; drop_missing
644644
if i isa Int
645645
param_buf[i] = p
646646
else
647-
param_buf[i] = collect(p)
647+
i = (first(i)::Int):(last(i)::Int)
648+
for (buf_i, p_i) in zip(i, SU.stable_eachindex(p))
649+
param_buf[buf_i] = p[p_i]
650+
end
648651
end
649652
elseif haskey(ic.initials_idx, p)
650653
i = ic.initials_idx[p]
651654
if i isa Int
652655
initials_buf[i] = p
653656
else
654-
initials_buf[i] = collect(p)
657+
i = (first(i)::Int):(last(i)::Int)
658+
for (buf_i, p_i) in zip(i, SU.stable_eachindex(p))
659+
initials_buf[buf_i] = p[p_i]
660+
end
655661
end
656662
elseif haskey(ic.constant_idx, p)
657663
i, j = ic.constant_idx[p]

lib/ModelingToolkitBase/src/systems/system.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,7 +1176,7 @@ end
11761176
11771177
Get the metadata associated with key `k` in system `sys` or `default` if it does not exist.
11781178
"""
1179-
function SymbolicUtils.getmetadata(sys::AbstractSystem, k::DataType, default)
1179+
function SymbolicUtils.getmetadata(sys::AbstractSystem, @nospecialize(k::DataType), default)
11801180
meta = get_metadata(sys)
11811181
return get(meta, k, default)
11821182
end
@@ -1188,7 +1188,7 @@ Set the metadata associated with key `k` in system `sys` to value `v`. This is a
11881188
out-of-place operation, and will return a shallow copy of `sys` with the appropriate
11891189
metadata values.
11901190
"""
1191-
function SymbolicUtils.setmetadata(sys::AbstractSystem, k::DataType, v)
1191+
function SymbolicUtils.setmetadata(sys::AbstractSystem, @nospecialize(k::DataType), @nospecialize(v))
11921192
meta = get_metadata(sys)
11931193
meta = Base.ImmutableDict(meta, k => v)::MetadataT
11941194
return @set sys.metadata = meta

lib/ModelingToolkitBase/src/systems/systems.jl

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,12 @@ function observed2graph(sys::AbstractSystem, eqs::Vector{Equation}, unknowns::Ve
983983
return graph, assigns
984984
end
985985

986+
"""
987+
Toggle to control whether `topsort_equations` prints the equations in the
988+
cycle, if present.
989+
"""
990+
TOPSORT_EQS_PRINT_CYCLE::Bool = false
991+
986992
"""
987993
$(TYPEDSIGNATURES)
988994
@@ -1054,7 +1060,37 @@ function topsort_equations(sys::AbstractSystem, eqs::Vector{Equation}, unknowns:
10541060
end
10551061
end
10561062

1057-
(check && idx != neqs) && throw(ArgumentError("The equations have at least one cycle."))
1063+
if check && idx != neqs
1064+
# Build a directed eq→eq subgraph over unsorted equations, find smallest SCC.
1065+
if TOPSORT_EQS_PRINT_CYCLE
1066+
unsorted = findall(>(0), degrees)
1067+
unsorted_set = Set(unsorted)
1068+
n_unsorted = length(unsorted)
1069+
old_to_new = Dict(old => new for (new, old) in enumerate(unsorted))
1070+
1071+
g = SimpleDiGraph(n_unsorted)
1072+
for src_old in unsorted
1073+
for dst_old in 𝑑neighbors(graph, assigns[src_old])
1074+
dst_old in unsorted_set || continue
1075+
add_edge!(g, old_to_new[src_old], old_to_new[dst_old])
1076+
end
1077+
end
1078+
1079+
sccs = strongly_connected_components(g)
1080+
nontrivial = filter(scc -> length(scc) >= 2, sccs)
1081+
smallest_new = isempty(nontrivial) ? collect(1:n_unsorted) :
1082+
nontrivial[argmin(length.(nontrivial))]
1083+
1084+
println("=== topsort_equations: CYCLE DETECTED ===")
1085+
println("Smallest cycle ($(length(smallest_new)) equations):")
1086+
for new_idx in smallest_new
1087+
old_idx = unsorted[new_idx]
1088+
println(" LHS = $(unknowns[assigns[old_idx]])")
1089+
println(" EQ = $(eqs[old_idx])")
1090+
end
1091+
end
1092+
throw(ArgumentError("The equations have at least one cycle."))
1093+
end
10581094

10591095
return ordered_eqs
10601096
end

lib/ModelingToolkitBase/test/initializationsystem.jl

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,15 @@ end
326326
initprob = ModelingToolkitBase.InitializationProblem(sys, 0.0; missing_guess_value)
327327
conditions = getfield.(equations(initprob.f.sys), :rhs)
328328

329-
@test initprob isa SCCNonlinearProblem
330-
@test initprob.probs isa Tuple{<:LinearProblem}
329+
# The init system as-is is linear. Since it is so severely overdetermined, MTK can sometimes
330+
# choose a bad simplification that results in a nonlinear system.
331+
# TODO: Support retaining `observed` equations in proper `mtkcompile` and generate
332+
# `x ~ Initial(x)` as such `observed` equations. This makes `mtkcompile`'s job easier
333+
# on initialization systems, but can lead to parameter-only equations.
334+
if !@isdefined(ModelingToolkit)
335+
@test initprob isa SCCNonlinearProblem
336+
@test initprob.probs isa Tuple{<:LinearProblem}
337+
end
331338
if @isdefined(ModelingToolkit)
332339
initsol = solve(initprob, reltol = 1.0e-12, abstol = 1.0e-12)
333340
@test SciMLBase.successful_retcode(initsol)

0 commit comments

Comments
 (0)