Expand description
The bordered (n+1) × (n+1) system, and why it is the one that works.
§Why not a bordered solve
The tempting cheap route is to keep the plain n × n Jacobian, reuse its
factorization, and recover Δλ by block elimination — two solves against
J plus a scalar. It is rejected on a mathematical basis, not a performance
one: J is exactly the matrix that goes singular at the nose, so the
Schur complement d − bᵀJ⁻¹c is the quotient of two quantities that both
vanish there. Every backend in this crate reports singularity only as a
non-finite result vector (sparse::RealSparseSystem::solve_values) and none
offers a condition estimate, so there is no way to detect the transition
either. The augmented matrix, by contrast, stays non-singular through the
nose.
§Why it stays non-singular
At a simple fold J has a one-dimensional null space span(v), and
transversality gives −Δs ∉ range(J). The bordered matrix
[ J -Δs ]
[ bᵀ d ]is then non-singular iff bᵀv ≠ 0. For Parametrization::PseudoArcLength
b = t_x, and at the nose t = (v, 0), so bᵀv = ‖v‖² ≠ 0. For
Parametrization::Local b = e_k with k = argmax|t_i| = argmax|v_i|, so
bᵀv = v_k ≠ 0. That is the entire reason this form exists.
§The border row must stay sparse, and this is measured
The λ column is emitted at every row regardless of whether Δs is zero
there, so the pattern does not depend on which buses carry load. That is
free: COLAMD’s dense_col threshold trips on it, the column is ordered last,
and the factors are then exactly the bordered factorization. Measured on
case1354pegase (n = 2449), a bordered solve with a sparse border row costs
1.4× a plain Newton solve.
The border row is a different story, and the naive choice is a disaster.
Emitting it densely — which Parametrization::PseudoArcLength genuinely
needs, since its row is the previous tangent — costs 92× the plain
solve at the same size, while the symbolic analysis stays at 1.0×. So this is
numeric fill during factorization, not a bad ordering, and no amount of
reasoning about COLAMD’s dense-row handling makes it go away. At 119 buses
the same comparison is 1.7×, which is why the problem is invisible on small
fixtures.
Hence Parametrization::Local is the default: its row is a single entry
e_k, and it carries the same transversality guarantee at the nose
(bᵀv = v_k ≠ 0, because k is chosen as the tangent’s largest component).
k changes rarely — far from the nose the tangent is dominated by λ, so
k = n and this degenerates to Natural; near the nose a voltage component
takes over — and a change costs one re-analysis, the same price a bus-type
change already pays.
So the pattern is fixed for as long as the continuation index is, rather
than for the whole segment. border_columns says which columns the row
occupies, and corrector::Segment re-analyzes when they change.
Structs§
- Augmented
Pattern - A
JacobianPatternplus the border, in one fixed emission order: the Jacobian’s own entries, then the λ column top to bottom, then the border row’s own columns in order. - Layout
- The Newton unknown layout, derived once per segment.
Enums§
- Parametrization
- Which equation closes the
npower-flow equations inn+1unknowns.
Functions§
- border_
columns - Which columns the border row structurally occupies, for a parametrization
whose continuation index is
kin a system ofnunknowns. - dominant_
index - The index of the tangent’s largest component — the unknown that is locally
the best continuation parameter, and the one
Parametrization::Localpins.