perf(gfql): undirected hop skips the whole-frame dedup of the doubled edge frame (#2026) - #2036
Conversation
|
Review wave 1 (quiet, 2,300 randomized direct-hop + 750 chain differentials on pandas/cuDF): the reverse-orientation self-loop filter compared the two endpoint columns and broke categorical endpoints with differing category sets; the filter is not load-bearing because every consumer dedups on the edge id, so 6745cd3 builds the plain concat of both orientations (what the polars hop does), which is also faster (block alone on 8M edges, local, unpublished: pandas 7.1 s → 1.4 s; cuDF 50 ms → 17 ms). Pins: categorical endpoints (pandas; cuDF cannot concat such categoricals on the base either), self-loop pin now exercises the multi-hop block, docstring/CHANGELOG corrected (entry moved under Performance, numbers labeled local). |
6812831 to
6745cd3
Compare
b3d6677 to
962f690
Compare
6745cd3 to
946586a
Compare
|
On the three questions (full analysis in the private plan,
|
946586a to
39d1134
Compare
|
READY (eed7de8) — rebased on master 9226829 after #2035 landed (the PR was CONFLICTING on CHANGELOG and The three design questions (asymptotics, load-bearing contracts, generalization) were answered on 2026-09-05 13:39Z from the audit; nothing new since. Receipts at eed7de8
|
eed7de8 to
26cde1d
Compare
|
CI at the rebased head 26cde1d: 77/77 check-runs success (tck-gfql, changed-line coverage, polars lane, hygiene guards included). Diff vs master unchanged in substance (hop.py 3 lines, the undirected-pairs pins, one CHANGELOG bullet, one test-lane registration); GPU receipt from eed7de8 carries over (product code identical). Ready to merge. |
…ting the doubled edge frame Every consumer of the doubled frame dedups on the edge id, so the whole-frame drop_duplicates over 2E rows (once per hop call, three times per chain) is redundant; the frame is now the plain concat the polars hop uses. Pins: set-oracle parity with self-loops, parallel edges and hub seeds on pandas, polars and cuDF; self-loops kept once through the multi-hop path; categorical endpoints with differing category sets on pandas. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WwMmVFo44ADiRRj5cxh1i1
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QztW7jYsDd66e8rb8pJNQA
26cde1d to
6abfb92
Compare
|
READY (6abfb92) — restacked onto master 8b208a6 after #2038 landed (the PR had gone CONFLICTING on the polars test-lane registration list next to #2038's line; union-resolved, one line each). The |
Stacked on #2028 → #2024. The #2026 follow-up, with a corrected root cause.
Finding. Profiling the undirected 2-hop chain after #2024 (pandas, 1M nodes / 8M edges, 50 hub seeds): the seed-rediscovery rule is 0.36 s of 10 s; the undirected pairs build in
hop.pyis 5.5 s. It concatenates both edge orientations over every edge (2E rows) and hash-deduplicates that frame on (from, to, edge id), once perhop()call and three times per chain (forward, reverse, final), independent of the neighborhood size.Fix. Every consumer of the doubled frame already dedups on the edge id (or the node id), so the frame is now the plain concat of both orientations, which is what the polars hop does. A review-wave differential (2,300 randomized direct-hop cases and 750 chains on pandas and cuDF: self-loops, parallel edges, null endpoints, string/float/int ids, duplicate indexes and bound edge ids, hops 1–3, fixed point, hop windows, wavefront, labels) found zero divergences from the previous implementation.
Measured locally (not a published number): the 2-hop chain 9.1 s → 3.3 s on pandas; the block alone on the 8M-edge frame 7.1 s → 1.4 s pandas, 50 ms → 17 ms cuDF. The published LiveJournal rows are the polars lane, which this does not change; the LJ re-measure adds the pandas arm.
Tests:
test_undirected_pairs_2026.py(set-oracle parity with self-loops, parallel edges and hub seeds for 1- and 2-hop on pandas, polars, cuDF; self-loops kept once through the multi-hop block; categorical endpoints with differing category sets on pandas). Hop/chain suites (test_hop, hop semantics pins, boundary matrix, seed rediscovery, scaling pin, chain, #1918 pins): 866 passed. Guards green.🤖 Generated with Claude Code
https://claude.ai/code/session_01WwMmVFo44ADiRRj5cxh1i1