@@ -153,13 +153,25 @@ function change_independent_variable(
153153 @set! sys. eqs = [get_eqs (sys); eqs] # add extra equations we derived
154154 @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)
155155
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+
156169 # Create a utility that performs the chain rule on an expression, followed by insertion of the new independent variable:
157170 # 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)
158171 function transform (ex:: T ) where {T}
159172 # 1) Replace the argument of every function; e.g. f(t) -> f(u(t))
160173 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))
163175 var_of_iv1 = var # e.g. f(t)
164176 var_of_iv2_of_iv1 = substitute (var_of_iv1, iv1 => iv2_of_iv1) # e.g. f(u(t))
165177 ex = substitute (ex, var_of_iv1 => var_of_iv2_of_iv1; fold)
0 commit comments