Skip to content

Commit 8edd588

Browse files
committed
Merge branch 'master' into myb/complete_ag
2 parents 650e629 + aed17f4 commit 8edd588

File tree

10 files changed

+86
-29
lines changed

10 files changed

+86
-29
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ModelingToolkit"
22
uuid = "961ee093-0014-501f-94e3-6117800e7a78"
33
authors = ["Yingbo Ma <[email protected]>", "Chris Rackauckas <[email protected]> and contributors"]
4-
version = "8.23.0"
4+
version = "8.24.0"
55

66
[deps]
77
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"

src/bipartite_graph.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ end
6363
function Base.setindex!(m::Matching{U}, v::Union{Integer, U}, i::Integer) where {U}
6464
if m.inv_match !== nothing
6565
oldv = m.match[i]
66-
isa(oldv, Int) && (m.inv_match[oldv] = unassigned)
66+
if isa(oldv, Int)
67+
@assert m.inv_match[oldv] == i
68+
m.inv_match[oldv] = unassigned
69+
end
6770
isa(v, Int) && (m.inv_match[v] = i)
6871
end
6972
return m.match[i] = v

src/inputoutput.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,8 @@ function inputs_to_parameters!(state::TransformationState, io)
269269
@assert new_v > 0
270270
new_var_to_diff[new_i] = new_v
271271
end
272-
@set! structure.var_to_diff = new_var_to_diff
273-
@set! structure.graph = new_graph
272+
@set! structure.var_to_diff = complete(new_var_to_diff)
273+
@set! structure.graph = complete(new_graph)
274274

275275
@set! sys.eqs = map(Base.Fix2(substitute, input_to_parameters), equations(sys))
276276
@set! sys.states = setdiff(states(sys), keys(input_to_parameters))

src/structural_transformation/StructuralTransformations.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ using ModelingToolkit: ODESystem, AbstractSystem, var_from_nested_derivative, Di
2121
ExtraVariablesSystemException,
2222
get_postprocess_fbody, vars!,
2323
IncrementalCycleTracker, add_edge_checked!, topological_sort,
24-
invalidate_cache!, Substitutions, get_or_construct_tearing_state
24+
invalidate_cache!, Substitutions, get_or_construct_tearing_state,
25+
AliasGraph
2526

2627
using ModelingToolkit.BipartiteGraphs
2728
import .BipartiteGraphs: invview

src/structural_transformation/pantelides.jl

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,37 @@ end
7474
7575
Perform Pantelides algorithm.
7676
"""
77-
function pantelides!(state::TransformationState; maxiters = 8000)
77+
function pantelides!(state::TransformationState, ag::Union{AliasGraph, Nothing} = nothing;
78+
maxiters = 8000)
7879
@unpack graph, solvable_graph, var_to_diff, eq_to_diff = state.structure
7980
neqs = nsrcs(graph)
8081
nvars = nv(var_to_diff)
8182
vcolor = falses(nvars)
8283
ecolor = falses(neqs)
8384
var_eq_matching = Matching(nvars)
8485
neqs′ = neqs
86+
nnonemptyeqs = count(eq -> !isempty(𝑠neighbors(graph, eq)), 1:neqs′)
87+
88+
# Allow matching for the highest differentiated variable that
89+
# currently appears in an equation (or implicit equation in a side ag)
90+
varwhitelist = falses(nvars)
91+
for var in 1:nvars
92+
if var_to_diff[var] === nothing
93+
while isempty(𝑑neighbors(graph, var)) && (ag === nothing || !haskey(ag, var))
94+
var′ = invview(var_to_diff)[var]
95+
var′ === nothing && break
96+
var = var′
97+
end
98+
if !isempty(𝑑neighbors(graph, var)) || (ag !== nothing && haskey(ag, var))
99+
varwhitelist[var] = true
100+
end
101+
end
102+
end
103+
104+
if nnonemptyeqs > count(varwhitelist)
105+
throw(InvalidSystemException("System is structurally singular"))
106+
end
107+
85108
for k in 1:neqs′
86109
eq′ = k
87110
isempty(𝑠neighbors(graph, eq′)) && continue
@@ -93,7 +116,6 @@ function pantelides!(state::TransformationState; maxiters = 8000)
93116
#
94117
# the derivatives and algebraic variables are zeros in the variable
95118
# association list
96-
varwhitelist = var_to_diff .== nothing
97119
resize!(vcolor, nvars)
98120
fill!(vcolor, false)
99121
resize!(ecolor, neqs)
@@ -103,11 +125,16 @@ function pantelides!(state::TransformationState; maxiters = 8000)
103125
pathfound && break # terminating condition
104126
for var in eachindex(vcolor)
105127
vcolor[var] || continue
106-
# introduce a new variable
107-
nvars += 1
108-
var_diff = var_derivative!(state, var)
109-
push!(var_eq_matching, unassigned)
110-
@assert length(var_eq_matching) == var_diff
128+
if var_to_diff[var] === nothing
129+
# introduce a new variable
130+
nvars += 1
131+
var_diff = var_derivative!(state, var)
132+
push!(var_eq_matching, unassigned)
133+
push!(varwhitelist, false)
134+
@assert length(var_eq_matching) == var_diff
135+
end
136+
varwhitelist[var] = false
137+
varwhitelist[var_to_diff[var]] = true
111138
end
112139

113140
for eq in eachindex(ecolor)

src/structural_transformation/partial_state_selection.jl

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
function partial_state_selection_graph!(state::TransformationState)
1+
function partial_state_selection_graph!(state::TransformationState;
2+
ag::Union{AliasGraph, Nothing} = nothing)
23
find_solvables!(state; allow_symbolic = true)
3-
var_eq_matching = complete(pantelides!(state))
4+
var_eq_matching = complete(pantelides!(state, ag))
45
complete!(state.structure)
56
partial_state_selection_graph!(state.structure, var_eq_matching)
67
end
@@ -86,6 +87,9 @@ function pss_graph_modia!(structure::SystemStructure, var_eq_matching, varlevel,
8687
filter!(eq -> invview(ict.graph.matching)[eq] === unassigned, to_tear_eqs)
8788
tearEquations!(ict, solvable_graph.fadjlist, to_tear_eqs, BitSet(to_tear_vars),
8889
nothing)
90+
for var in to_tear_vars
91+
var_eq_matching[var] = unassigned
92+
end
8993
for var in to_tear_vars
9094
var_eq_matching[var] = ict.graph.matching[var]
9195
end
@@ -119,12 +123,15 @@ function partial_state_selection_graph!(structure::SystemStructure, var_eq_match
119123
end
120124

121125
varlevel = map(1:ndsts(graph)) do var
122-
level = 0
126+
graph_level = level = 0
123127
while var_to_diff[var] !== nothing
124128
var = var_to_diff[var]
125129
level += 1
130+
if !isempty(𝑑neighbors(graph, var))
131+
graph_level = level
132+
end
126133
end
127-
level
134+
graph_level
128135
end
129136

130137
inv_varlevel = map(1:ndsts(graph)) do var
@@ -138,7 +145,7 @@ function partial_state_selection_graph!(structure::SystemStructure, var_eq_match
138145

139146
# TODO: Should pantelides just return this?
140147
for var in 1:ndsts(graph)
141-
if var_to_diff[var] !== nothing
148+
if varlevel[var] !== 0
142149
var_eq_matching[var] = unassigned
143150
end
144151
end

src/structural_transformation/symbolics_tearing.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ function tearing_reassemble(state::TearingState, var_eq_matching; simplify = fal
567567
eq_to_diff = new_eq_to_diff
568568
diff_to_var = invview(var_to_diff)
569569

570-
@set! state.structure.graph = graph
570+
@set! state.structure.graph = complete(graph)
571571
@set! state.structure.var_to_diff = var_to_diff
572572
@set! state.structure.eq_to_diff = eq_to_diff
573573
@set! state.fullvars = fullvars = fullvars[invvarsperm]

src/systems/connectors.jl

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -198,25 +198,39 @@ function connection2set!(connectionsets, namespace, ss, isouter)
198198
end
199199
end
200200

201-
function generate_connection_set(sys::AbstractSystem)
201+
function generate_connection_set(sys::AbstractSystem, find = nothing, replace = nothing)
202202
connectionsets = ConnectionSet[]
203-
sys = generate_connection_set!(connectionsets, sys)
203+
sys = generate_connection_set!(connectionsets, sys, find, replace)
204204
sys, merge(connectionsets)
205205
end
206206

207-
function generate_connection_set!(connectionsets, sys::AbstractSystem, namespace = nothing)
207+
function generate_connection_set!(connectionsets, sys::AbstractSystem, find, replace,
208+
namespace = nothing)
208209
subsys = get_systems(sys)
209210

210211
isouter = generate_isouter(sys)
211212
eqs′ = get_eqs(sys)
212213
eqs = Equation[]
213214

214215
cts = [] # connections
216+
extra_states = []
215217
for eq in eqs′
216-
if eq.lhs isa Connection
217-
push!(cts, get_systems(eq.rhs))
218+
lhs = eq.lhs
219+
rhs = eq.rhs
220+
if find !== nothing && find(rhs, namespace)
221+
neweq, extra_state = replace(rhs, namespace)
222+
if extra_state isa AbstractArray
223+
append!(extra_states, unwrap.(extra_state))
224+
elseif extra_state !== nothing
225+
push!(extra_states, extra_state)
226+
end
227+
neweq isa AbstractArray ? append!(eqs, neweq) : push!(eqs, neweq)
218228
else
219-
push!(eqs, eq) # split connections and equations
229+
if lhs isa Number || lhs isa Symbolic
230+
push!(eqs, eq) # split connections and equations
231+
else
232+
push!(cts, get_systems(rhs))
233+
end
220234
end
221235
end
222236

@@ -235,7 +249,10 @@ function generate_connection_set!(connectionsets, sys::AbstractSystem, namespace
235249
end
236250

237251
# pre order traversal
238-
@set! sys.systems = map(s -> generate_connection_set!(connectionsets, s,
252+
if !isempty(extra_states)
253+
@set! sys.states = [get_states(sys); extra_states]
254+
end
255+
@set! sys.systems = map(s -> generate_connection_set!(connectionsets, s, find, replace,
239256
renamespace(namespace, nameof(s))),
240257
subsys)
241258
@set! sys.eqs = eqs
@@ -305,8 +322,9 @@ function generate_connection_equations_and_stream_connections(csets::AbstractVec
305322
eqs, stream_connections
306323
end
307324

308-
function expand_connections(sys::AbstractSystem; debug = false, tol = 1e-10)
309-
sys, csets = generate_connection_set(sys)
325+
function expand_connections(sys::AbstractSystem, find = nothing, replace = nothing;
326+
debug = false, tol = 1e-10)
327+
sys, csets = generate_connection_set(sys, find, replace)
310328
ceqs, instream_csets = generate_connection_equations_and_stream_connections(csets)
311329
_sys = expand_instream(instream_csets, sys; debug = debug, tol = tol)
312330
sys = flatten(sys, true)

src/systems/systemstructure.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ function TearingState(sys; quick_cancel = false, check = true)
350350
eq_to_diff = DiffGraph(nsrcs(graph))
351351

352352
return TearingState(sys, fullvars,
353-
SystemStructure(var_to_diff, eq_to_diff, graph, nothing), Any[])
353+
SystemStructure(complete(var_to_diff), complete(eq_to_diff),
354+
complete(graph), nothing), Any[])
354355
end
355356

356357
function linear_subsys_adjmat(state::TransformationState)

test/structural_transformation/utils.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ StructuralTransformations.find_solvables!(state)
2121
sss = state.structure
2222
@unpack graph, solvable_graph, var_to_diff = sss
2323
@test graph.fadjlist == [[1, 7], [2, 8], [3, 5, 9], [4, 6, 9], [5, 6]]
24-
@test graph.badjlist == 9
24+
@test length(graph.badjlist) == 9
2525
@test ne(graph) == nnz(incidence_matrix(graph)) == 12
2626
@test nv(solvable_graph) == 9 + 5
2727
let N = nothing

0 commit comments

Comments
 (0)