Skip to content

Latest iteration on ngrams#138

Merged
aneubeck merged 11 commits into
mainfrom
aneubeck/fasterngrams
Jul 16, 2026
Merged

Latest iteration on ngrams#138
aneubeck merged 11 commits into
mainfrom
aneubeck/fasterngrams

Conversation

@aneubeck

Copy link
Copy Markdown
Collaborator

Note: I might test a different table with more bigrams from a fresh index...
But that requires integration with the reindex code and comparing actually disk size.

@aneubeck aneubeck requested a review from a team as a code owner July 14, 2026 16:28
Copilot AI review requested due to automatic review settings July 14, 2026 16:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors sparse-ngrams to reduce bigram-priority memory footprint and to speed up extraction by removing per-gram slicing/hashing, replacing it with (1) a compact factored bigram-priority model and (2) a rolling 8-byte window for NGram construction.

Changes:

  • Replace the old lazily-built 256×256 bigram table with a compact factored model (BIGRAM_H + packed 4-bit per-bigram correction).
  • Redesign NGram to pack (len + payload) into 27 bits with a bijective mixing permutation; update extraction to build grams from a rolling u64 window.
  • Update docs/benchmarks and add a frozen benchmark fixture corpus; remove the old deque.rs implementation.
Show a summary per file
File Description
crates/sparse-ngrams/src/table.rs Replaces full bigram lookup table with a compact factored bigram-priority model and adds tests.
crates/sparse-ngrams/src/ngram.rs Redesigns NGram encoding (27-bit packed + mix/unmix), changes constructors, and updates tests/debug formatting.
crates/sparse-ngrams/src/lib.rs Updates crate docs and re-exports bigram_priority; removes old table-size constant export.
crates/sparse-ngrams/src/extract.rs Reworks extraction to use rolling window + rolling bigram priority; updates brute-force reference + tests.
crates/sparse-ngrams/src/deque.rs Deletes the old fixed deque implementation (no longer used).
crates/sparse-ngrams/README.md Updates algorithm/model documentation and performance notes to match the new implementation.
crates/sparse-ngrams/benchmarks/performance.rs Switches benchmark input to a frozen fixture file.
crates/sparse-ngrams/benchmarks/fixtures/sample_code.txt Adds a committed “large” benchmark corpus to prevent benchmark drift.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 8/11 changed files
  • Comments generated: 5
  • Review effort level: Low

Comment thread crates/sparse-ngrams/src/ngram.rs
Comment on lines +150 to 155
/// Whether this represents an empty gram. Valid n-grams are always at least 2 bytes long, so
/// this only holds for a default-constructed placeholder.
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
Comment thread crates/sparse-ngrams/src/extract.rs
Comment thread crates/sparse-ngrams/src/extract.rs
Comment thread crates/sparse-ngrams/README.md Outdated
/// so the masked lookup (`b & 0x7f`) merely returns a value that the next step discards.
#[inline]
pub(crate) fn bigram_priority_rolling(a: u8, b: u8, h_a: u32) -> (u32, u32) {
let h_b = BIGRAM_H[(b & (BIGRAM_ALPHABET as u8 - 1)) as usize] as u32;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplication of bigram_h below.


The current bigram table contains the 5,845 most frequent bigrams from a large code corpus.
The table saturates quickly — the first ~1,600 bigrams already capture 99% of the unique n-grams.
Priorities come from a compact factored model (~8.5 KB) rather than a full 256×256 lookup table (~64 KB in memory). The ASCII bigram `(a, b)` is scored as `H[a] + H[b] + (code << 10) + 1`, where `H` is a shared 128-entry per-byte weight and `code` is a 4-bit per-bigram correction; a per-bigram index folded into the low bits makes every priority unique while a higher score still means a more frequent bigram. The model was trained offline against a frequency ranking from a large code corpus (~1.4% inversions vs. the exact ranking).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be committed?

Comment thread crates/sparse-ngrams/src/table.rs Outdated
aneubeck and others added 2 commits July 16, 2026 15:17
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@aneubeck aneubeck enabled auto-merge July 16, 2026 13:25
@aneubeck aneubeck disabled auto-merge July 16, 2026 13:25
@aneubeck aneubeck enabled auto-merge July 16, 2026 13:25
@aneubeck aneubeck merged commit 7c179c3 into main Jul 16, 2026
8 checks passed
@aneubeck aneubeck deleted the aneubeck/fasterngrams branch July 16, 2026 13:26
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.

3 participants