brainy/tests/unit/hnsw
David Snelling 72df5572b7 perf(8.0): HNSW removeItem is O(in-degree) via a reverse-adjacency index
removeItem() scanned the ENTIRE corpus on every delete to find nodes that
referenced the removed id (and to repair edges left asymmetric by pruning), so a
delete was O(N) and a bulk delete O(N²) — on the open-core JS vector path that
serves when no native provider is registered.

Maintain a reverse-adjacency index (`target → level → set of nodes that link to
target`), so removeItem touches only the removed node's actual in-neighbors:
O(in-degree) per delete, O(N·degree) for a bulk delete. The index is lazily
built, maintained incrementally at every forward-edge mutation (add-link and
prune), and invalidated (rebuilt on next use) by the bulk paths (cold-load
restore + clear). New tests assert the three invariants that matter for a
reverse index: no dangling references to deleted nodes, the incrementally-
maintained index exactly equals a fresh rebuild from the live adjacency, and
search still returns the survivors' true nearest neighbours (exact vs brute force).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 11:06:22 -07:00
..
allowed-ids-pushdown.test.ts feat(8.0): asOf at-gen vector defer — provider-served historical semantic search (#35) 2026-06-23 15:52:09 -07:00
connections-codec.test.ts feat: graph link compression — delta-varint connections (2.4.0 #3) 2026-05-28 10:37:47 -07:00
lazy-vectors.test.ts feat(8.0): zero-config finalize + cut JS quantization (config.vector = recall + persistMode) 2026-06-15 10:08:51 -07:00
remove-reverse-adjacency.test.ts perf(8.0): HNSW removeItem is O(in-degree) via a reverse-adjacency index 2026-06-29 11:06:22 -07:00