Skip to content

Inline linear SCC emits an inconsistent runtime system (rank 14/15, ‖Ax−b‖/‖b‖ ≈ 1) at a consistent state — integration goes Unstable #98

Description

@baggepinnen

Summary

The inline-linear-SCC pass emits runtime A \ b terms under the implicit contract that the linear system is solvable at runtime. On MultibodyComponents.examples.suspension.HalfCar (22 states, emitted blocks [13, 15, 12, 13, 15, 12, 295]), two of the small blocks are rank-deficient with b outside the range of A — measured at a fully consistent initialization point (initialization residual ~4e-10, found with LM + pivoted QR):

# min-norm pivoted-QR solve of the emitted (A, b) at runtime:
n=15 rank=14 relres=0.945     # ‖A x − b‖ / ‖b‖ ≈ 1: b ⟂ range(A)
n=13 rank=12 relres=0.952     # same block family, later during integration
n=13 rank=12 relres=0.0       # rank-deficient but CONSISTENT — harmless
n=295 rank=295 relres=1.4e-14 # the big block (#95) is full-rank and fine here

With the stock INLINE_LINEAR_SCC_OP = (\) this is a SingularException or, via the DyadCompilerPasses LinearSolve path (JuliaComputing/DyadCompilerPasses.jl#41), garbage that silently feeds the ODE RHS. Either way the torn variables of that block do not satisfy their equations, so the dynamics are wrong; we observe immediate Unstable (dt → 1e-21) on integration from a consistent state, with a smooth RHS and a clean FD Jacobian (max|J| ≈ 1.7e5, constant in the FD step size).

Why this looks like a construction bug rather than a model property

  • The state is on the constraint manifold to ~1e-10, so a correctly-assembled linearization of consistent equations should be consistent to roundoff, not to O(1).
  • A 100% relative residual on a 15×15 block means one redundant row's RHS contradicts the others — the shape you'd get if an eliminated row's contribution to b is mis-accounted. __reduce_linear_system!'s handling of eliminated equations (reworked in fix: handle eliminated equations in inline linear SCCs appropriately #94) and the constants/aliases topological update would be my first suspects.
  • The sibling 13×13 block with the same rank deficiency is consistent (relres = 0), so rank deficiency per se (static reaction indeterminacy) is expected and fine; the inconsistency is the anomaly.

Reproduction

HalfCar from MultibodyComponents.jl with maybe_zeros set on the joint-axis parameter vectors (16 arrays), optimize=:basic, and a rank-revealing override of the runtime linear solve to measure rank/relres (probe script available on request — it is the same setup as the measurements posted on #97 and #95). Versions: StateSelection main @ 3d10ed7 (also with #97 merged — identical numbers), ModelingToolkitTearing v1.14.1, MTK master v11.x.

Related: #95 (block size), #97 (measured there), JuliaComputing/DyadCompilerPasses.jl#41 (what the runtime does when the solve fails).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions