@@ -153,13 +153,25 @@ function change_independent_variable(
153
153
@set! sys. eqs = [get_eqs (sys); eqs] # add extra equations we derived
154
154
@set! sys. unknowns = [get_unknowns (sys); [iv1, div2_of_iv1]] # add new variables, will be transformed to e.g. t(u) and uˍt(u)
155
155
156
+ # A utility function that returns whether var (e.g. f(t)) is a function of iv (e.g. t)
157
+ function is_function_of (var, iv)
158
+ # Peel off outer calls to find the argument of the function of
159
+ if iscall (var) && operation (var) === getindex # handle array variables
160
+ var = arguments (var)[1 ] # (f(t))[1] -> f(t)
161
+ end
162
+ if iscall (var)
163
+ var = only (arguments (var)) # e.g. f(t) -> t
164
+ return isequal (var, iv)
165
+ end
166
+ return false
167
+ end
168
+
156
169
# Create a utility that performs the chain rule on an expression, followed by insertion of the new independent variable:
157
170
# e.g. (d/dt)(f(t)) -> (d/dt)(f(u(t))) -> df(u(t))/du(t) * du(t)/dt -> df(u)/du * uˍt(u)
158
171
function transform (ex:: T ) where {T}
159
172
# 1) Replace the argument of every function; e.g. f(t) -> f(u(t))
160
173
for var in vars (ex; op = Nothing) # loop over all variables in expression (op = Nothing prevents interpreting "D(f(t))" as one big variable)
161
- is_function_of_iv1 = iscall (var) && isequal (only (arguments (var)), iv1) # of the form f(t)?
162
- if is_function_of_iv1 && ! isequal (var, iv2_of_iv1) # prevent e.g. u(t) -> u(u(t))
174
+ if is_function_of (var, iv1) && ! isequal (var, iv2_of_iv1) # of the form f(t)? but prevent e.g. u(t) -> u(u(t))
163
175
var_of_iv1 = var # e.g. f(t)
164
176
var_of_iv2_of_iv1 = substitute (var_of_iv1, iv1 => iv2_of_iv1) # e.g. f(u(t))
165
177
ex = substitute (ex, var_of_iv1 => var_of_iv2_of_iv1; fold)
@@ -207,15 +219,15 @@ function change_independent_variable(
207
219
connector_type = get_connector_type (sys)
208
220
assertions = Dict (transform (ass) => msg for (ass, msg) in get_assertions (sys))
209
221
wascomplete = iscomplete (sys) # save before reconstructing system
222
+ wassplit = is_split (sys)
223
+ wasflat = isempty (systems)
210
224
sys = typeof (sys)( # recreate system with transformed fields
211
225
eqs, iv2, unknowns, ps; observed, initialization_eqs,
212
226
parameter_dependencies, defaults, guesses, connector_type,
213
227
assertions, name = nameof (sys), description = description (sys)
214
228
)
215
229
sys = compose (sys, systems) # rebuild hierarchical system
216
230
if wascomplete
217
- wasflat = isempty (systems)
218
- wassplit = is_split (sys)
219
231
sys = complete (sys; split = wassplit, flatten = wasflat) # complete output if input was complete
220
232
end
221
233
return sys
0 commit comments