@@ -241,6 +241,32 @@ function substitute_lower_order!(state::TearingState)
241241
242242end
243243
244+ # Documenting the differences to structural simplification for discrete systems:
245+ # In discrete systems the lowest-order term is x_k-i, instead of x(t). In order
246+ # to substitute dummy variables for x_k-1, x_k-2, ... instead you need to reverse
247+ # the order. So for discrete systems `var_order` is defined a little differently.
248+ #
249+ # The orders will also be off by one. The reason this is is that the dynamics of
250+ # the system should be given in terms of Shift(t, 1)(x(t), x(t-1), ...). But
251+ # having the observables be indexed by the next time step is not so nice. So we
252+ # handle the shifts in the renaming, rather than explicitly.
253+ #
254+ # The substitution should look like the following:
255+ # x(t) -> Shift(t, 1)(x(t))
256+ # x(k-1) -> x(t)
257+ # x(k-2) -> x_{t-1}(t)
258+ # x(k-3) -> x_{t-2}(t)
259+ # and so on...
260+ #
261+ # In the implicit discrete case this shouldn't happen. The simplification should
262+ # look like a NonlinearSystem.
263+ #
264+ # For discrete systems Shift(t, 2)(x(t)) is not equivalent to Shift(t, 1)(Shift(t,1)(x(t))
265+ # This is different from the continuous case where D(D(x)) can be substituted for
266+ # by iteratively substituting x_t ~ D(x), then x_tt ~ D(x_t). For this reason the
267+ # total_sub dict is updated at the time that the renamed variables are written,
268+ # inside the loop where new variables are generated.
269+
244270import ModelingToolkit: Shift
245271function tearing_reassemble (state:: TearingState , var_eq_matching,
246272 full_var_eq_matching = nothing ; simplify = false , mm = nothing , cse_hack = true , array_hack = true )
@@ -318,9 +344,6 @@ function tearing_reassemble(state::TearingState, var_eq_matching,
318344 diff_to_var[dv] = nothing
319345 end
320346 end
321- @show var_eq_matching
322-
323- println (" Post state selection." )
324347
325348 # `SelectedState` information is no longer needed past here. State selection
326349 # is done. All non-differentiated variables are algebraic variables, and all
@@ -330,26 +353,27 @@ function tearing_reassemble(state::TearingState, var_eq_matching,
330353 is_solvable = let solvable_graph = solvable_graph
331354 (eq, iv) -> eq isa Int && iv isa Int && BipartiteEdge (eq, iv) in solvable_graph
332355 end
333- idx_to_lowest_shift = Dict {Int, Int} (var => 0 for var in 1 : length (fullvars))
334- for (i,var) in enumerate (fullvars)
335- key = (operation (var) isa Shift) ? only (arguments (var)) : var
336- idx_to_lowest_shift[i] = get (lowest_shift, key, 0 )
356+
357+ if is_only_discrete (state. structure)
358+ idx_to_lowest_shift = Dict {Int, Int} (var => 0 for var in 1 : length (fullvars))
359+ for (i,var) in enumerate (fullvars)
360+ key = (operation (var) isa Shift) ? only (arguments (var)) : var
361+ idx_to_lowest_shift[i] = get (lowest_shift, key, 0 )
362+ end
337363 end
338364
339365 # if var is like D(x)
340366 isdervar = let diff_to_var = diff_to_var
341367 var -> diff_to_var[var] != = nothing
342368 end
343- # For discrete variables, we want the substitution to turn
344- # Shift(t, k)(x(t)) => x_t-k(t)
345369 var_order = let diff_to_var = diff_to_var
346370 dv -> begin
347371 order = 0
348372 while (dv′ = diff_to_var[dv]) != = nothing
349373 order += 1
350374 dv = dv′
351375 end
352- is_only_discrete (state. structure) && (order = - idx_to_lowest_shift[dv] - order - 1 )
376+ is_only_discrete (state. structure) && (order = - idx_to_lowest_shift[dv] - order)
353377 order, dv
354378 end
355379 end
@@ -403,6 +427,7 @@ function tearing_reassemble(state::TearingState, var_eq_matching,
403427 linear_eqs = mm === nothing ? Dict {Int, Int} () :
404428 Dict (reverse (en) for en in enumerate (mm. nzrows))
405429
430+ total_sub = Dict ()
406431 for v in 1 : length (var_to_diff)
407432 is_highest_discrete = begin
408433 var = fullvars[v]
@@ -442,8 +467,13 @@ function tearing_reassemble(state::TearingState, var_eq_matching,
442467 end
443468 dx = fullvars[dv]
444469 # add `x_t`
445- order, lv = var_order (dv)
470+ println ()
471+ @show order, lv = var_order (dv)
446472 x_t = lower_name (fullvars[lv], iv, order)
473+ @show fullvars[v]
474+ @show fullvars[dv]
475+ @show fullvars[lv]
476+ @show dx, x_t
447477 push! (fullvars, simplify_shifts (x_t))
448478 v_t = length (fullvars)
449479 v_t_idx = add_vertex! (var_to_diff)
@@ -466,11 +496,16 @@ function tearing_reassemble(state::TearingState, var_eq_matching,
466496 add_edge! (solvable_graph, dummy_eq, dv)
467497 @assert nsrcs (graph) == nsrcs (solvable_graph) == dummy_eq
468498 @label FOUND_DUMMY_EQ
469- is_only_discrete (state. structure) && (idx_to_lowest_shift[v_t] = idx_to_lowest_shift[dv])
499+ is_only_discrete (state. structure) && begin
500+ idx_to_lowest_shift[v_t] = idx_to_lowest_shift[dv]
501+ operation (dx) isa Shift && (total_sub[dx] = x_t)
502+ order == 1 && (total_sub[x_t] = fullvars[var_to_diff[dv]])
503+ end
470504 var_to_diff[v_t] = var_to_diff[dv]
471505 var_eq_matching[dv] = unassigned
472506 eq_var_matching[dummy_eq] = dv
473507 end
508+ @show total_sub
474509
475510 # Will reorder equations and unknowns to be:
476511 # [diffeqs; ...]
@@ -490,15 +525,13 @@ function tearing_reassemble(state::TearingState, var_eq_matching,
490525 # Solve solvable equations
491526 println ()
492527 println (" SOLVING SOLVABLE EQUATIONS." )
493- @show eq_var_matching
494528 toporder = topological_sort (DiCMOBiGraph {false} (graph, var_eq_matching))
495529 eqs = Iterators. reverse (toporder)
496- @show eqs
497- @show neweqs
498- @show fullvars
499- total_sub = Dict ()
500530 idep = iv
531+ @show eq_var_matching
532+
501533 for ieq in eqs
534+ println ()
502535 iv = eq_var_matching[ieq]
503536 if is_solvable (ieq, iv)
504537 # We don't solve differential equations, but we will need to try to
@@ -513,7 +546,6 @@ function tearing_reassemble(state::TearingState, var_eq_matching,
513546 dx = D (simplify_shifts (lower_name (
514547 fullvars[lv], idep, order - 1 )))
515548 @show dx
516- @show neweqs[ieq]
517549 eq = dx ~ simplify_shifts (Symbolics. fixpoint_sub (
518550 Symbolics. symbolic_linear_solve (neweqs[ieq],
519551 fullvars[iv]),
0 commit comments