@@ -69,6 +69,95 @@ function pantelides_reassemble(state::TearingState, var_eq_matching)
69
69
return sys
70
70
end
71
71
72
+ """
73
+ computed_highest_diff_variables(var_to_diff, ag)
74
+
75
+ Computes which variables are the "highest-differentiated" for purposes of
76
+ pantelides. Ordinarily this is relatively straightforward. However, in our
77
+ case, there are two complicating conditions:
78
+
79
+ 1. We allow variables in the structure graph that don't appear in the
80
+ system at all. What we are interested in is the highest-differentiated
81
+ variable that actually appears in the system.
82
+
83
+ 2. We have an alias graph. The alias graph implicitly contributes an
84
+ alias equation, so it doesn't actually whitelist any additional variables,
85
+ but it may change which variable is considered the highest differentiated one.
86
+ Consider the following situation:
87
+
88
+ Vars: x, y
89
+ Eqs: 0 = f(x)
90
+ Alias: ẋ = ẏ
91
+
92
+ In the absence of the alias, we would consider `x` to be the highest
93
+ differentiated variable. However, because of the alias (and because there
94
+ is no alias for `x=y`), we actually need to take `ẋ` as the highest
95
+ differentiated variable.
96
+
97
+ This function takes care of these complications are returns a boolean array
98
+ for every variable, indicating whether it is considered "highest-differentiated".
99
+ """
100
+ function computed_highest_diff_variables (structure, ag:: Union{AliasGraph, Nothing} )
101
+ @unpack graph, var_to_diff = structure
102
+
103
+ nvars = length (var_to_diff)
104
+ varwhitelist = falses (nvars)
105
+ for var in 1 : nvars
106
+ if var_to_diff[var] === nothing && ! varwhitelist[var]
107
+ # This variable is structurally highest-differentiated, but may not actually appear in the
108
+ # system (complication 1 above). Ascend the differentiation graph to find the highest
109
+ # differentiated variable that does appear in the system or the alias graph).
110
+ while isempty (𝑑neighbors (graph, var)) && (ag === nothing || ! haskey (ag, var))
111
+ var′ = invview (var_to_diff)[var]
112
+ var′ === nothing && break
113
+ var = var′
114
+ end
115
+ # If we don't have an alias graph, we are done. If we do have an alias graph, we may
116
+ # have to keep going along the stem, for as long as our differentiation path
117
+ # matches that of the stem (see complication 2 above). Note that we may end up
118
+ # whitelisting multiple differentiation levels of the stem here from different
119
+ # starting points that all map to the same stem. We clean that up in a post-processing
120
+ # pass below.
121
+ if ag != = nothing && haskey (ag, var)
122
+ (_, stem) = ag[var]
123
+ stem == 0 && continue
124
+ # Ascend the stem
125
+ while isempty (𝑑neighbors (graph, var))
126
+ var′ = invview (var_to_diff)[var]
127
+ var′ === nothing && break
128
+ stem′ = invview (var_to_diff)[var]
129
+ # Invariant from alias elimination: Stem is chosen to have
130
+ # the highest differentiation order.
131
+ @assert stem′ != = nothing
132
+ if ! haskey (ag, var′) || ag[var′][2 ] != stem′
133
+ varwhitelist[stem] = true
134
+ break
135
+ end
136
+ stem = stem′
137
+ var = var′
138
+ end
139
+ else
140
+ varwhitelist[var] = true
141
+ end
142
+ end
143
+ end
144
+
145
+ # Remove any variables from the varwhitelist for whom a higher-differentiated
146
+ # var is already on the whitelist.
147
+ for var in 1 : nvars
148
+ varwhitelist[var] || continue
149
+ var′ = var
150
+ while (var′ = var_to_diff[var′]) != = nothing
151
+ if varwhitelist[var′]
152
+ varwhitelist[var] = false
153
+ break
154
+ end
155
+ end
156
+ end
157
+
158
+ return varwhitelist
159
+ end
160
+
72
161
"""
73
162
pantelides!(state::TransformationState; kwargs...)
74
163
@@ -86,27 +175,7 @@ function pantelides!(state::TransformationState, ag::Union{AliasGraph, Nothing}
86
175
nnonemptyeqs = count (eq -> ! isempty (𝑠neighbors (graph, eq)) && eq_to_diff[eq] === nothing ,
87
176
1 : neqs′)
88
177
89
- # Allow matching for the highest differentiated variable that
90
- # currently appears in an equation (or implicit equation in a side ag)
91
- varwhitelist = falses (nvars)
92
- for var in 1 : nvars
93
- if var_to_diff[var] === nothing && ! varwhitelist[var]
94
- while isempty (𝑑neighbors (graph, var)) && (ag === nothing || ! haskey (ag, var))
95
- var′ = invview (var_to_diff)[var]
96
- var′ === nothing && break
97
- var = var′
98
- end
99
- if ! isempty (𝑑neighbors (graph, var))
100
- if ag != = nothing && haskey (ag, var)
101
- # TODO : remove lower diff vars from whitelist
102
- c, a = ag[var]
103
- iszero (c) || (varwhitelist[a] = true )
104
- else
105
- varwhitelist[var] = true
106
- end
107
- end
108
- end
109
- end
178
+ varwhitelist = computed_highest_diff_variables (state. structure, ag)
110
179
111
180
if nnonemptyeqs > count (varwhitelist)
112
181
throw (InvalidSystemException (" System is structurally singular" ))
0 commit comments