Matching-Based CCA Pairing: a Negative Result#
pairing_frustration.md diagnosed the CCA
pairing bottleneck: in the hard regime, 97.4% of failures (38/39) had a
valid alternative pairing available in the same cluster pool that greedy
first-fit never considered. This page reports the implementation and
benchmarking of the direct response — exact maximum-cardinality matching
in place of greedy first-fit — and its outcome: no measurable
improvement (+0.2 percentage points over 4200 trials). The cause is
identified in the Discussion. The result is reported in the same manner
as the project’s prior negative results (candidate ordering, pair
prefilters, Γ-expansion, FFT docking, soft relaxation,
densify_method="voronoi").
Method#
pyfracval/cca/matching.py adds two alternatives to
_generate_pairs()’s greedy first-fit, selected via the
cca_pairing_strategy config flag ("greedy" default, "matching",
"matching_leaf_weighted"):
max_cardinality_matching: exact maximum-cardinality matching via memoized brute-force DP. Round pool sizes are small (bounded by roughly1/n_subcl_percentage, empirically ≤16), so this is cheap and exact; a Blossom-algorithm implementation is unnecessary at this scale.leaf_weighted_matching: the same matching, with total edge weight (from a per-cluster-pair leaf classification, reusingcandidates.py’s per-particle leaf mask aggregated into a per-cluster leaf fraction) as a tiebreaker among cardinality-optimal solutions. Cardinality is optimized first and never sacrificed for weight, since giving up a matchable pair for a higher-weight edge would directly contradict the diagnosed problem.
Both operate over the same inexpensive gamma-feasibility graph
_generate_pairs()’s greedy loop already builds (gamma_real and gamma_pc < sum_rmax, with the existing 10% relaxation fallback) —
deliberately not the graph pairing_frustration_probe.py builds for
offline diagnosis, which tests every edge by attempting production
sticking (3 retries each). That census is appropriate for a one-off
diagnostic; running it inside _generate_pairs() on the hot path would
be prohibitively slow and would perturb the RNG state real trials
depend on. This design constraint turns out to explain the negative
result — see Discussion.
Results#
Single-shot (frustration-probe regime and seeds)#
benchmarks/pairing_strategy_frustration_rerun.py: same hard and
easy-control regimes, same 40 seeds, same single-shot (no internal
retry) methodology as the original probe, varying only
cca_pairing_strategy.
Regime |
greedy |
matching |
matching_leaf_weighted |
|---|---|---|---|
Hard (Df=2.25, kf=0.95, σ=1.9) |
2.5% (1/40) |
5.0% (2/40) |
2.5% (1/40) |
Easy control (Df=1.8, kf=1.0, σ=1.5) |
100% (40/40) |
100% (40/40) |
100% (40/40) |
A one-trial difference at n=40 is not distinguishable from noise. Plain matching does not measurably outperform greedy first-fit; leaf-weighted matching performs identically to greedy on these seeds.
Retry-inclusive boundary sweep#
benchmarks/pairing_strategy_sweep.py --config configs/hard_regime_boundary_sweep.toml --strategies matching: the full
840-combination, 4200-trial grid from
hard_regime_boundary_sweep.md, run with
cca_pairing_strategy="matching" and compared cell-by-cell against the
greedy baseline (same literal seeds 1–5 per combination in both runs).
Strategy |
Total successes |
|---|---|
greedy (baseline) |
3039/4200 (72.4%) |
matching |
3048/4200 (72.6%) |
The net difference is +9 trials (+0.2 percentage points) across the grid. Of the 840 combinations, 51 (6.1%) differ at all between the two strategies, and the differences run in both directions in roughly equal measure (largest single swing +3 at one cell, against several −2 and +2 swings elsewhere). There is no systematic improvement concentrated anywhere in the grid; the pattern is consistent with noise from each internal-retry attempt consuming a different amount of shared RNG state once the pairing decision diverges between strategies, even from the same literal seed.
matching_leaf_weighted was not re-run at full-grid scale: the
single-shot comparison above shows it performing identically to greedy
on the exact seeds where an effect was expected, and a second 4200-trial
run for a strategy with no signal in the targeted test was not
considered a justified use of the compute budget.
Raw output: benchmark_results/pairing_strategy_frustration_rerun.json,
benchmark_results/hard_regime_boundary_sweep_matching/.
Discussion#
The 97.4% “rescuable” figure from
pairing_frustration.md was computed against a
feasibility graph built from actual sticking outcomes (each edge tested
via the real production sticking path, 3 retries). Matching over that
graph would find rescuing pairings in nearly every case — that is what
the diagnostic showed. But _generate_pairs() cannot afford to build
that graph: it runs before any geometry has been attempted, using only
the inexpensive gamma-feasibility test (gamma_pc < sum_rmax), which is
a necessary but not sufficient condition for two clusters sticking
without overlap. The cheap graph is systematically denser and more
optimistic than the real one. Maximizing cardinality over the
too-permissive graph does not preferentially select edges that succeed
at the sticking stage; it selects a different feasible-looking pairing,
which fails at approximately the same rate as greedy’s first-fit choice,
because both draw from the same pool of geometrically plausible pairs
without information about which the sticking search will resolve.
The same argument explains the absence of a leaf-weighting effect: the weighting can only re-rank among cardinality-optimal solutions within the same optimistic graph, and carries no additional information about sticking outcomes.
The lever the diagnosis actually identified — repartnering when a chosen
pair fails to stick, using outcome information a precomputed graph does
not have — is a different design: backtracking within _run_iteration
rather than a smarter upfront graph. That design is implemented and
evaluated in backtracking_pairing.md.
Status#
cca_pairing_strategy="matching"/"matching_leaf_weighted" are
implemented, tested (tests/test_cca_matching.py), and available as
opt-in config values. They do not move hard-regime success rates and are
not promoted beyond opt-in.