Skip to content

perf(ZIBR): single-pass relabel-and-sum for pure bus merges#330

Open
luke-kiernan wants to merge 1 commit into
fix/zibr-per-branch-l2from
perf/zibr-single-pass-merge
Open

perf(ZIBR): single-pass relabel-and-sum for pure bus merges#330
luke-kiernan wants to merge 1 commit into
fix/zibr-per-branch-l2from
perf/zibr-single-pass-merge

Conversation

@luke-kiernan

Copy link
Copy Markdown
Collaborator

Stacked on #329. Removes the Build-Ybus regression that #329's correctness fix surfaced.

Why

#329's per-branch L2 criterion correctly merges low-impedance branches that the old iszero(real(Y)) gate skipped. On main these large systems merged 0 buses, so the reduction short-circuited (isempty(reduction) && return ybus); now they merge a handful (28 on the Eastern Interconnect), which makes the merge machinery hot for the first time.

That machinery — _merge_ybus_buses!_accumulate_csc_col_into! — sums each removed bus's row/column into its survivor with per-entry CSC structural inserts, each of which shifts the whole backing store of a 78k×78k matrix, then slices out the removed buses with data[bus_ix, bus_ix]. Cost scales with merges × nnz.

Measured (Eastern, 78,484 buses, same machine):

Build Ybus merged
main ~313 ms 0
#329 (slow merge) ~505 ms 28
this branch ~375 ms 28

Residual merge overhead over the no-merge baseline drops from ~140–190 ms to ~40 ms.

What

A pure bus merge (only ZIBR produces one — radial/Ward add admittances, degree-two adds series branches) is just an index relabeling, so the merge and the bus-removal slice are fused into a single O(nnz) pass: relabel each entry's row/column to the surviving index and let sparse() sum collisions. Adjacency is rebuilt the same way, then re-derived for survivors (anti-parallel branches cancel in the signed sum, mirroring the existing repair).

  • Guarded by _is_pure_merge_reduction (merges present; no removed_buses/series_branch_map/removed_arc_to_surviving_bus/added maps). The general elimination path is untouched, so radial/degree-two/Ward are byte-for-byte unchanged.
  • Each reduction is its own _apply_reduction call, so the fast path fires on the ZIBR step even when other reductions follow it.

Tests

  • New ZIBR fast merge matches a rewire-and-rebuild oracle: merging bus 3 into bus 2 across a zero-impedance line equals an independently built system where bus 3's branch is rewired onto bus 2 and the ZI line removed (the huge ZI entries cancel in the row/column sum).
  • Full reduction suite (ZIBR, anti-parallel, radial, degree-two, Ward, composition, 14-bus combos) — 33k assertions — passes, including the adjacency-sensitive anti-parallel merge keeps a bus's degree.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Performance Results

Precompile Time

Main This Branch Delta
2.2 s 2.1 s -2.1%

Execution Time

Cells show median (min–max) over 5 samples; delta compares medians.

Test Main This Branch Delta
matpower_ACTIVSg2000_sys-Build Ybus 9.1 (9.0–11.3) ms 9.9 (9.8–12.6) ms +9.2%
matpower_ACTIVSg2000_sys-Build PTDF 72.1 (71.5–72.5) ms 74.0 (72.7–77.8) ms +2.7%
matpower_ACTIVSg2000_sys-Build LODF 145.9 (144.6–149.7) ms 151.0 (148.9–152.5) ms +3.5%
matpower_ACTIVSg2000_sys-Build VirtualMODF 90.5 (90.3–94.8) ms 1.0 (1.0–1.0) s +1024.5%
matpower_ACTIVSg2000_sys-VirtualMODF Query 10 rows 0.6 (0.5–1.3) ms 0.7 (0.7–1.6) ms +15.2%
matpower_ACTIVSg2000_sys-Radial network reduction 0.7 (0.7–1.0) ms 0.9 (0.9–1.2) ms +22.6%
matpower_ACTIVSg2000_sys-Degree two network reduction 0.9 (0.9–1.4) ms 1.0 (1.0–1.6) ms +2.1%
Base_Eastern_Interconnect_515GW-Build Ybus 526.2 (522.8–555.2) ms 607.3 (604.9–626.6) ms +15.4%
Base_Eastern_Interconnect_515GW-Build VirtualPTDF 762.9 (761.2–765.0) ms 834.8 (832.2–840.5) ms +9.4%
Base_Eastern_Interconnect_515GW-VirtualPTDF Query 10 rows 24.2 (23.9–24.3) ms 25.3 (24.9–25.5) ms +4.3%
Base_Eastern_Interconnect_515GW-Build VirtualMODF 759.9 (754.5–761.3) ms 922.6 (918.9–922.9) ms +21.4%
Base_Eastern_Interconnect_515GW-VirtualMODF Query 10 rows 28.7 (28.3–29.0) ms 29.5 (29.1–30.1) ms +2.5%
Base_Eastern_Interconnect_515GW-Radial network reduction 33.1 (32.9–34.2) ms 33.3 (32.9–33.8) ms +0.5%
Base_Eastern_Interconnect_515GW-Degree two network reduction 47.8 (47.4–48.8) ms 50.0 (47.6–50.9) ms +4.5%

@luke-kiernan luke-kiernan force-pushed the perf/zibr-single-pass-merge branch from 59c222b to 555185b Compare June 18, 2026 19:24
The bus merge applied by ZeroImpedanceBranchReduction went through
`_merge_ybus_buses!`, which does per-entry CSC structural inserts to sum each
removed bus's row/column into its survivor, followed by a `data[bus_ix, bus_ix]`
slice. On a large sparse Ybus each insert shifts the whole backing store, so the
cost scales with merges × nnz. On main these systems merged 0 buses (the old
`iszero(real(Y))` gate), so the path was skipped via the empty-reduction
short-circuit; the per-branch L2 criterion now correctly merges low-impedance
branches (e.g. 28 on the Eastern Interconnect), making this path hot.

A pure bus merge (no eliminations or admittance additions — only ZIBR produces
one) is just an index relabeling, so the merge and the bus-removal slice are
fused into a single O(nnz) pass: relabel each entry's row/column to the surviving
index and let `sparse()` sum collisions. Adjacency is rebuilt the same way, then
re-derived for survivors (anti-parallel branches cancel in the signed sum). The
general elimination path (radial/degree-two/Ward) is unchanged.

Eastern Interconnect Build Ybus: ~505 ms -> ~375 ms (residual merge overhead
~140 ms -> ~40 ms). Adds a rewire-and-rebuild oracle test; all reduction tests
(33k assertions) pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@luke-kiernan luke-kiernan force-pushed the perf/zibr-single-pass-merge branch 3 times, most recently from ef11ed8 to 658a561 Compare June 18, 2026 22:08
@luke-kiernan luke-kiernan force-pushed the fix/zibr-per-branch-l2 branch from 4b86712 to c919d37 Compare June 18, 2026 22:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant