Structural Transformation

Developer API

These APIs support ModelingToolkit's structural-transformation machinery and extension packages. They are version-controlled for ModelingToolkit developers; end-user applications should use the documented public simplification API instead.

These functions are used for structural analysis and transformation of equation systems, including index reduction, tearing, and other algebraic manipulations used in the simplification process.

The names below are versioned developer API. TearingState is mutable compiler state and its fields are intentionally opaque. find_solvables! is retained as a compatibility export; new code should call the documented transformation entry points instead.

Tearing and Algebraic Simplification

ModelingToolkit.StructuralTransformations.tearing_substitutionFunction
tearing_substitution(sys::AbstractSystem; kwargs...)

Replace the equations of sys with its fully substituted equations.

This is a structural-transformation helper used by simplification passes. End-user code should usually call ModelingToolkitBase.mtkcompile.

Arguments

  • sys: system whose equations should be substituted.
  • kwargs...: keyword arguments forwarded to full_equations.

Returns

A copy of sys with substituted equations and no cached schedule.

source
StateSelection.find_solvables!Function
find_solvables!(
    state::StateSelection.TransformationState;
    kwargs...
)

Populate state.structure.solvable_graph with information about the solvability of equations. The implementation should validate that state.structure.solvable_graph is nothing before modifying state. The default implementation relies on find_eq_solvables!, to which it forwards all keyword arguments.

source

Index Reduction

ModelingToolkit.StructuralTransformations.pantelides_reassembleFunction
pantelides_reassemble(state::TearingState, var_eq_matching)

Reassemble a System after Pantelides index reduction.

Arguments

  • state: tearing state containing the original system and derivative graphs.
  • var_eq_matching: variable-equation matching returned by the Pantelides pass.

Returns

A system whose equations and unknowns include the differentiated equations selected by the Pantelides algorithm.

source

Incidence Matrix Operations

ModelingToolkit.StructuralTransformations.but_ordered_incidenceFunction
but_ordered_incidence(ts::TearingState, varmask = highest_order_variable_mask(ts))

Construct the block upper triangular ordered incidence matrix for ts.

Arguments

  • ts: tearing state to analyze.
  • varmask: predicate selecting which variable indices participate in the ordering.

Returns

A pair (matrix, block_boundaries) containing the ordered incidence matrix and the starting row/column boundaries for each block.

source

Variable Ordering and Masks

In-Place Compilation

ModelingToolkit.mtkcompile!Function
mtkcompile!(state::TearingState; kwargs...)

Mutating structural simplification entry point for an existing tearing state.

This is developer-facing API used by ModelingToolkit internals and extension packages that already have a TearingState. User code should normally call ModelingToolkitBase.mtkcompile on a System instead.

Arguments

  • state: tearing state to simplify in place.

Keyword Arguments

  • check_consistency: whether to check the transformed system for structural consistency.
  • fully_determined: whether the transformed system is expected to have a square equation/unknown structure.
  • inputs: variables to treat as external inputs.
  • outputs: variables to treat as requested outputs.
  • disturbance_inputs: input variables that should be treated as disturbances.
  • kwargs...: additional simplification options forwarded to the internal compiler.

Returns

The simplified System.

source
ModelingToolkitTearing.TearingStateType
mutable struct TearingState <: StateSelection.TransformationState{System}

An implementation of StateSelection.TransformationState for ModelingToolkitBase.System.

Fields

  • sys::System: The system of equations.

  • fullvars::Vector{SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}}: The set of variables of the system.

  • structure::ModelingToolkitTearing.SystemStructure

  • extra_eqs::Vector{Equation}

  • param_derivative_map::Dict{SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}, SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}}

  • no_deriv_params::Set{SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}}

  • original_eqs::Vector{Equation}

  • additional_observed::Vector{Equation}: Additional user-provided observed equations. The variables calculated here are not used in the rest of the system.

  • always_present::BitVector: Corresponding to fullvars, marks variables which may not be structurally present in any equation according to structure.graph but should not be considered as unused. This is typically used by variables on the RHS of equations in additional_observed, and is useful for ensuring the consistency check is valid. For example, a simplification pass prior to StateSelection.check_consistency may process the equations
    a ~ b
    b ~ c
    c ~ a
    Into additional_observed = [a ~ b, c ~ b], and thus end up in a state where there are no equations and fullvars = [b]. The consistency check would consider b as unused and the system as fully determined, but in reality b should be considered as used and the system singular.
  • statemachines::Vector{System}

  • eqs_source::Vector{Vector{Symbol}}: Source information for each equation in the TearingState. Vector{Symbol} for each equation representing the path of the subsystem to which it belongs. Empty entries indicate unknown source. If this field is empty, either the system has no equations or source information is unknown.

  • mm::Union{Nothing, StateSelection.CLIL.SparseMatrixCLIL{Int64, Int64}}: A SparseMatrixCLIL identifying equations which are integer-coefficient linear combinations of variables.
  • analytical_derivatives::Dict{SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}, SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}}: A mapping from D(x) (not the toterm variant) to its derivative expression for analytically eliminated differential variables. No integrated or differentiated form of x should be present in the equations if its derivative specified here. Effectively, x along with all its integrated and differentiated forms must be eliminated as observed and put into additional_observed.
source

Structural Transformation Interfaces

These upstream interfaces are rendered here because the ModelingToolkit structural transformation developer API dispatches on them.

StateSelection.TransformationStateType
abstract type TransformationState{T}

Supertype for structs representing the state of a system of DAEs during structural transformations. Must have the following fields:

  • structure<:SystemStructure: A SystemStructure subtype. Should ideally be concretely typed to a specific implementation.
  • fullvars::AbstractVector{T}: A list of variables in the system, ordered identically to the destination vertices of structure.graph. The eltype of this buffer can be chosen by the implementor. If this field is not present, get_fullvars must be implemented for the type.

In addition to the structural information in structure, this struct typically contains information relevant to the symbolic structure of the system. This can be used to reconstruct the system for code-generation after structural transformations.

source
StateSelection.TearingAlgorithmType
abstract type TearingAlgorithm

Supertype for all tearing algorithms. A tearing algorithm takes as input the SystemStructure along with any other necessary arguments.

The output of a tearing algorithm must be a TearingResult and a NamedTuple of any additional data computed in the process that may be useful for further processing.

source
StateSelection.TearingResultType
struct TearingResult

A struct containing the results of tearing.

Fields

  • var_eq_matching::BipartiteGraphs.Matching{Union{BipartiteGraphs.Unassigned, SelectedState}, Vector{Union{BipartiteGraphs.Unassigned, SelectedState, Int64}}}: The variable-equation matching. Differential variables are matched to SelectedState. The derivative of a differential variable is matched to the corresponding differential equation. Solved variables are matched to the equation they are solved from. Algebraic variables are matched to unassigned.
  • full_var_eq_matching::BipartiteGraphs.Matching{Union{BipartiteGraphs.Unassigned, SelectedState}, Vector{Union{BipartiteGraphs.Unassigned, SelectedState, Int64}}}: The variable-equation matching prior to tearing. This is the maximal matching used to compute var_sccs (see below). For generating the torn system, var_eq_matching is the source of truth. This should only be used to identify algebraic equations in each SCC.
  • var_sccs::Vector{Vector{Int64}}: The partitioning of variables into strongly connected components (SCCs). The SCCs are sorted in dependency order, so each SCC depends on variables in previous SCCs.
source
StateSelection.find_eq_solvables!Function
find_eq_solvables!(state::TransformationState, ieq::Int; kwargs...)

Identify which variables equation ieq can be rearranged to solve for, and populate state.structure.solvable_graph accordingly. Keyword arguments are left to the implementor, and can influence the criteria for solvability.

source
StateSelection.bareiss.bareiss!Function
bareiss!(M, [swap_strategy])

Perform Bareiss's fraction-free row-reduction algorithm on the matrix M. Optionally, a specific pivoting method may be specified.

swapstrategy is an optional argument that determines how the swapping of rows and columns is performed. bareisscolswap (the default) swaps the columns and rows normally. bareiss_virtcolswap pretends to swap the columns which can be faster for sparse matrices.

source
StateSelection.CLIL.SparseMatrixCLILType
SparseMatrixCLIL{T, Ti}

The SparseMatrixCLIL represents a sparse matrix in two distinct ways:

  1. As a sparse (in both row and column) n x m matrix
  2. As a row-dense, column-sparse k x m matrix

The data structure keeps a permutation between the row order of the two representations. Swapping the rows in one does not affect the other.

On construction, the second representation is equivalent to the first with fully-sparse rows removed, though this may cease being true as row permutations are being applied to the matrix.

The default structure of the SparseMatrixCLIL type is the second structure, while the first is available via the thin AsSubMatrix wrapper.

source
ModelingToolkitTearing.InlineLinearSystemType
struct InlineLinearSystem

Description of a single inline linear-solve block in a simplified system: a square linear system $A x = b$ that the generated code re-solves on every evaluation. The tearing/reassemble pass emits such a block when it solves a strongly-connected component of algebraic equations as one linear system, writing each solved variable as an assignment vᵢ ~ (A \ b)[i].

Fields

  • size::Int64: Dimension N of the square N×N linear system.

  • variables::Vector{SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}}: The variables solved by the block, ordered by their index in the solution vector. An entry is nothing if that solution component is not assigned to a variable (it should not normally occur).

  • expression::SymbolicUtils.BasicSymbolicImpl.var"typeof(BasicSymbolicImpl)"{SymReal}: The symbolic solve expression A \ b (its arguments are the coefficient matrix A and the right-hand side b), retained so callers can inspect or numerically evaluate A, e.g. to check its conditioning.

See inline_linear_systems.

source
ModelingToolkitTearing.inline_linear_systemsFunction
inline_linear_systems(
    sys::ModelingToolkitBase.AbstractSystem
) -> Vector{InlineLinearSystem}

Report the inline linear-solve blocks in the simplified system sys as a Vector{InlineLinearSystem}, sorted by decreasing size.

When tearing solves a strongly-connected component of algebraic equations as one linear system, it emits, into equations(sys) / observed(sys), a square system $A x = b$ that the generated code re-solves on every evaluation as A \ b. Each solution component i then appears as an assignment vᵢ ~ (A \ b)[i]. The reassemble pass records these blocks in the system metadata as it creates them, and this function simply reads them back.

For each block it reports its size N and the N variables it solves for. It is a diagnostic for understanding a compiled model's per-step cost and structure: large blocks are the dominant linear-algebra work each evaluation, and a singularity-prone block can be traced to the physical quantities it determines. Returns an empty vector when sys emits no inline linear solves.

source