Sinkhorn-Knopp doubly-stochastic normalization at a fixed iteration count wastes compute on dense matrices and under-serves sparse ones, measured directly.
Sinkhorn-Knopp (SK) is the standard way to push a matrix of positive numbers toward doubly stochastic: alternately normalize every row, then every column, and repeat. It shows up across manifold-constrained hyper-connections (mHC, arXiv:2512.24880) and other neural-network mixing schemes as a fixed 20-iteration budget. This gist measures what that fixed budget actually buys, at 5/10/20/50 iterations, on two synthetic matrix regimes chosen to sit on either side of the density phase transition He (arXiv:2507.09711) identifies for Sinkhorn-Knopp convergence. In CCF, SK-style normalization is used only as a gauge/presentation step, never as the causal trust-transfer update itself, which is a separate quotient-affine contraction (QAC) step. This run stays entirely inside the presentation-layer question.
CCF's runtime-certified trust transfer (Prov6, US 64/092,485) separates the causal update from any normalization or gauge-fixing step that sits near it in a pipeline ([0099]-[0101]). This run supports that separation with a direct measurement: the cost of a gauge step like SK is not a fixed, portable number, which is exactly why a certificate must not be conflated with the presentation step next to it.
See crates/research/sk-presentation-cost/ (branch research/nightly/2026-07-10-sk-presentation-cost). Zero external dependencies: a hand-rolled xorshift64* PRNG makes every matrix and benchmark reproducible from a seed. Key design decision: sinkhorn_knopp(matrix, iters) records the doubly-stochasticity residual after every pass, so one run yields the whole convergence curve instead of a single endpoint measurement.
Take a table of positive numbers and reshape it so every row and every column adds up to the same total, a balanced version of whatever the numbers represent. The standard trick: divide each row by its total, then each column by its total, repeat. How many repeats is enough varies with how lopsided the table was to start. An even table balances almost immediately, and extra repeats past that point do nothing. A lopsided table, where one number per row dominates, needs far more repeats, and even a lot of extra effort leaves it measurably less balanced than the easy table ever was. Getting the repeat count wrong doesn't break anything else, but it does mean wasted computation on one side and a falsely tidy-looking number on the other.
Dara runs the night shift on an assembly line with six coordination robots. Each reports a weight for how much it should factor its neighbors' recent actions into its own next move. Balancing those weights gives Dara's dashboard a clean read on who is actually coordinating with whom. On a normal night the six robots hand off evenly, and the balancing settles almost instantly. The fixed pass count the plant has used for months is already more than needed. Then a sensor on robot 4 misreports, and robot 4 starts weighting one neighbor almost completely while ignoring the rest. The same fixed pass count that was overkill on a normal night falls far short now: the dashboard shows "mostly balanced" when the real pattern is badly skewed, and nobody notices until a supervisor checks the raw weights hours later. A smarter balancing algorithm alone would not have caught this. Checking the actual imbalance each night, instead of trusting one fixed pass count to have handled every night's data the same way, would have.
| Approach | Iteration count | Regime-aware? | Source |
|---|---|---|---|
| mHC (parent method) | Fixed 20 | No | arXiv:2512.24880 |
| mHC-lite | 0 (exact BvN construction) | Not applicable, replaces SK entirely | arXiv:2601.05732 |
| go-mHC | 0 (direct orthostochastic parameterization) | Not applicable | arXiv:2604.02309 |
| This run | Measured at 5/10/20/50, both regimes | Yes, measures the gap directly | this crate |
cargo run --release -p sk-presentation-cost --bin sk-bench, n=64, 200 repeats per cell:
| regime | iters | ns/full-run | residual |
|---|---|---|---|
| dense | 5 | 73,994 | 5.231e-13 |
| dense | 10 | 146,873 | 6.661e-16 |
| dense | 20 | 295,038 | 5.551e-16 |
| dense | 50 | 740,767 | 5.551e-16 |
| sparse | 5 | 75,326 | 3.426e-1 |
| sparse | 10 | 148,595 | 1.112e-1 |
| sparse | 20 | 296,155 | 3.600e-2 |
| sparse | 50 | 736,930 | 1.617e-2 |
Cost scales linearly with iteration count in both regimes. Quality does not. At the mHC anchor of 20 iterations, dense is already 10 iterations past its own plateau, while sparse is still two orders of magnitude worse than dense achieves at iteration 5. Full table across n in {32, 64, 128} is in the crate's RESULTS.txt.
This measures presentation quality, not trust. A balanced matrix says nothing about whether the underlying weights should be trusted. The dense/sparse split is a simplified proxy for He's density statistic, not a computation of it. Benchmarks ran on one development machine, not a dedicated bench server, so treat the nanosecond figures as indicative, not certified. The residual figures are exact and reproducible from the seed.
- Repo: github.com/Hulupeep/CCF
- Branch:
research/nightly/2026-07-10-sk-presentation-cost - Crate:
crates/research/sk-presentation-cost/ - Specflow: github.com/Hulupeep/Specflow
- More: floutlabs.com and theshyrobot.com
BSL 1.1, converting to Apache 2.0 in 2032. Contact via floutlabs.com.