Skip to content

perf: break citation cycles one tangle at a time - #48

Merged
hedmana merged 1 commit into
mainfrom
perf/acyclic
Sep 29, 2026
Merged

hedmana merged 1 commit into
mainfrom
perf/acyclic

Conversation

@hedmana

@hedmana hedmana commented Sep 29, 2026

Copy link
Copy Markdown
Owner

Closes #47

What

acyclic breaks each strongly connected component in one pass. It lays the component's works out newest first and keeps only the citations running forward in that order, so a citation of a later work, the one most at odds with publication order, is still what goes first. Among works of the same year, the one its peers cite most is placed as the earliest.

Why

The old loop ran find_cycle over the whole ancestry once per removed edge. Every ranking on the expanded snapshot paid for that, including each /lineage request.

Ancestry before after
GraphSAGE, served snapshot 5.6 s 0.10 s
GCN, served snapshot 6.1 s 0.08 s
GraphSAGE, with recovered citations 12.2 s 0.11 s

It removes slightly more edges than before, 237 against 202 of GraphSAGE's roughly 40,000. The old loop's picks among same-year cycles depended on the order find_cycle happened to walk. The result is a DAG either way.

Verify

uv run pytest tests/test_score.py tests/test_originators.py tests/test_api.py
curl localhost:8000/lineage/gnn/W2624431344   # well under a second

Generated with Claude Code

@hedmana
hedmana merged commit cab5e1a into main Sep 29, 2026
4 checks passed
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.

Cycle breaking takes seconds per ranking on the expanded snapshot

1 participant