Skip to content

Commit 80849cf

Browse files
committed
Make pantelides robust against unused derivative vars
This doesn't ordinarily happen, but for efficiency, I sometimes want to keep around differentiated variables that turn out not to actually be present in any equations. In this case, pantelides needs to make sure to only consider the highest order differentiated variable that *does* appear in an equation.
1 parent 03d8b04 commit 80849cf

File tree

7 files changed

+45
-15
lines changed

7 files changed

+45
-15
lines changed

src/inputoutput.jl

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

274274
@set! sys.eqs = map(Base.Fix2(substitute, input_to_parameters), equations(sys))
275275
@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: 3 additions & 2 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

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/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)