pub fn detect_blocks(
dim: usize,
irn: &[Index],
jcn: &[Index],
) -> Option<Vec<i32>>Expand description
Find a block-diagonal-plus-border partition in an assembled KKT, or None.
The border of an arrowhead KKT is its high-degree columns: every block
touches them, so their degree grows with the block count while a block’s own
columns keep a fixed degree. Peel the top-k by degree for geometrically
growing k, and accept the first k that leaves a partition worth having.
“Worth having” is deliberately strict, because engaging this path on a matrix that merely can be cut buys nothing and costs a border solve:
- the peeled columns must stand out — the smallest peeled degree at least
DEGREE_GAPtimes the median degree. A chain has no such gap, and removing any interior column of a chain splits it, so without this a plain tridiagonal matrix “detects” as blocks; - at least
MIN_BLOCKSblocks, and a border under 5% of the matrix; - no block holding half the interior.
A separating set found this way can be larger than necessary (the peel is geometric), so it is then shrunk: a peeled column whose neighbours all lie in one block belongs in that block.
Measured on a 210k-variable N-1 SCOPF this recovers the model’s own structure exactly — 259 shared columns, 65 blocks — without being told.
irn / jcn are the 1-based lower-triangle triplet.