Skip to content

Layout transitions/constraints + 4 new engines, algorithm coverage tail, pathfinding perf, docs bundle - #28

Merged
davidkpiano merged 15 commits into
mainfrom
best-lib-sweep
Jun 12, 2026
Merged

Layout transitions/constraints + 4 new engines, algorithm coverage tail, pathfinding perf, docs bundle#28
davidkpiano merged 15 commits into
mainfrom
best-lib-sweep

Conversation

@davidkpiano

@davidkpiano davidkpiano commented Jun 12, 2026

Copy link
Copy Markdown
Member

Closes out the full gap list. Three changesets (2 minor, 1 patch). pnpm verify green end-to-end: typecheck, 1,682 tests in 72 files (all real engines, including WASM Graphviz and headless cytoscape), build, publint, and the package smoke test exercising all nine layout entry points against the packed tarball in a clean consumer.

Note: PR #25 (layout adapters) had been merged into the already-merged bench-harness branch and never reached main; #26 landed it first. This PR builds on that.

Visual

  • genLayoutTransition(from, to) — the layout-morphing primitive: yields interpolated LayoutFrames between two layouts (drive with applyLayoutFrame, one per rAF). Lay out with dagre, re-lay out with ELK, tween live. Layouts are plain data here, so this falls out of the model — see docs/layout-transitions.md.
  • Geometry utilitiestranslateGraph / centerGraph (mutable, hierarchy-aware: parent-relative children and container-relative edge routes are left alone via LCA check).
  • constraints.layer — first portable, advisory layout constraint: ELK partitions, Graphviz rank=same, others ignore. Per-engine escape hatches remain.
  • Four new adapters (now 8 total, each an optional-peer subpath):
    • layout/forceatlas2 — graphology FA2, seeded determinism, native pinning, edge weights
    • layout/d3-hierarchy — Reingold–Tilford tidy tree; forests; non-tree edges preserved via spanning-tree layout
    • layout/webcola — constraint-based, overlap avoidance, deterministic per seed, DAG flow
    • layout/cytoscape — headless bridge to the whole cytoscape layout ecosystem (+ caller-registered extensions via injectable cy)
  • ELK adapter now maps seedelk.randomSeed (was silently ignored for force/stress); dagre peer widened to ^3 || ^4 (devDep tests 3.x).

Analytical

  • k-core (getCoreNumbers/getKCore, Batagelj–Zaveršnik O(m)), Katz centrality, eigenvector centrality hardened ((A+I)-shifted iteration fixes bipartite oscillation; differential-tested vs graphology), isBipartite + Hopcroft–Karp getMaximumBipartiteMatching, getMinCut (shares the max-flow solver; value === getMaxFlow().value by construction), seeded label propagation, and generators (createCompleteGraph/createGridGraph/createRandomGraph, deterministic per seed).

Performance (patch changeset)

  • Lazy path materialization: genShortestPaths reconstructs a path only when yielded (verified failing-first with edge-read-counting proxies).
  • Typed-array binary heap in the Dijkstra/A*/bidirectional hot loops.
  • Measured (10k nodes, medians): −70% first-path-then-abandon, −41% all-targets, −71% single-target early exit. Bench script: bench/paths-lazy.ts.

Docs (docs/*.md)

layout.md (full guide: contract, 8 engines, constraints matrix, worker recipes), layout-transitions.md, algorithms.md (70-function reference with complexity), benchmarks.md (honest scoreboard — includes our losses: degree sweep is 4–23× slower than ngraph/graphology, a known follow-up), migrating-from-graphlib.md (all 11 alg.* functions have equivalents), react-flow-elk-pipeline.md. README synced (peers table, guides index, honest routing claims — only ELK/dagre/Graphviz route edges).

Known follow-ups (not in this PR)

  • Degree-sweep perf gap vs ngraph/graphology (from benchmarks)
  • toXYFlow writes edge labels to data.label, not React Flow's top-level label render prop (documented workaround in the pipeline doc; candidate model-level fix)

…eline cookbook; fix JSDoc subpaths in format examples
…ing (Hopcroft–Karp), min-cut, seeded LPA, graph generators
…range ^3||^4; docs: layout guide + transitions
…s (148ms -> 9.7ms sweep at 100k/300k, parity with ngraph/graphology)
@davidkpiano

Copy link
Copy Markdown
Member Author

Follow-ups landed in this PR after all:

  • O(1) getDegree — the degree sweep was the one benchmark cell this library lost across the board (4–23× behind). Now |out| + |in| minus a cached non-directed self-loop count (revalidated by index version + mode, same scheme as the CSR snapshot): 148 ms → 9.7 ms at 100k/300k, parity with ngraph/graphology. Semantics pinned by the existing degree/mode suites.
  • xyflow labelstoXYFlow now emits edge labels as top-level edge.label (what React Flow/Svelte Flow render) and node labels as data.label (what the default node renders); fromXYFlow reads both back. Metadata round-trip unchanged. Minor changeset with migration note (edge.data.labeledge.label).
  • Benchmarks re-run + doc refreshed (2026-06-12): degree sweep now 1.1–2.3× of the leader, beating graphology in 3 of 4 100k cells; PageRank grid flipped to wins at 1k and 100k. Remaining honest losses are listed in the doc — ngraph still leads most degree cells.

pnpm verify + 1,683 tests green.

@davidkpiano davidkpiano changed the title Best-lib sweep: layout transitions/constraints + 4 new engines, algorithm coverage tail, pathfinding perf, docs bundle Layout transitions/constraints + 4 new engines, algorithm coverage tail, pathfinding perf, docs bundle Jun 12, 2026
@davidkpiano
davidkpiano merged commit 7a38641 into main Jun 12, 2026
5 checks passed
@github-actions github-actions Bot mentioned this pull request Jun 12, 2026
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