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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions