fast-bleu-cpp is a dependency-free, header-only C++17 library for computing
BLEU and SelfBLEU scores over pre-tokenized text. It is inspired by
fast-bleu, while providing a native
C++ API without Python, OpenMP, or platform-specific runtime dependencies.
The library caches reference n-gram statistics for repeated scoring. Its SelfBLEU implementation also caches per-sentence counts and the two largest reference counts, so each leave-one-out score does not rebuild the reference set.
Add the module to MODULE.bazel:
bazel_dep(name = "fast-bleu-cpp", version = "0.1.0")Then depend on its public target:
cc_binary(
name = "app",
srcs = ["app.cc"],
deps = ["@fast-bleu-cpp"],
)Your C++ target must compile as C++17 or newer.
#include "fast_bleu/bleu.hpp"
#include <iostream>
int main() {
const fast_bleu::Corpus references = {
{"the", "cat", "is", "on", "the", "mat"},
{"there", "is", "a", "cat", "on", "the", "mat"},
};
const fast_bleu::Sentence hypothesis =
{"the", "cat", "is", "on", "the", "mat"};
const fast_bleu::BleuScorer scorer(references);
std::cout << scorer.score(hypothesis) << '\n';
}BleuScorer is immutable after construction and can be reused to score a batch:
const fast_bleu::Corpus hypotheses = {hypothesis_a, hypothesis_b};
const std::vector<double> scores = scorer.score_all(hypotheses);For a one-off calculation, use fast_bleu::sentence_bleu.
The defaults are uniform BLEU-4 weights and NLTK method-1-style smoothing:
fast_bleu::Options options;
options.weights = {0.5, 0.5}; // BLEU-2
options.smoothing = fast_bleu::Smoothing::kAddEpsilon;
options.epsilon = 0.1;
const fast_bleu::BleuScorer scorer(references, options);Set smoothing to kNone when any missing weighted n-gram should make the score
zero. Set auto_reweight to reproduce NLTK's short-hypothesis behavior for the
default BLEU-4 weights.
Scores use standard modified n-gram precision, closest-reference length with a shorter-reference tie break, and the standard brevity penalty. Token boundaries are represented structurally, so tokens containing spaces cannot create an n-gram collision.
const fast_bleu::SelfBleuScorer scorer(sentences, options);
const std::vector<double> scores = scorer.scores();Each sentence is scored against every other sentence. At least two sentences are required.
- Inputs must already be tokenized; the library does not choose a tokenizer.
BleuScorercomputes sentence BLEU against one fixed reference set. It does not aggregate counts across aligned segments as corpus BLEU does.- Smoothing modes are no smoothing and NLTK method 1.
- All public calculations use
doubleprecision. This produces tiny differences from fast-bleu's published trigram examples, whose C++ boundary narrows weights tofloat; results match NLTK's double-precision calculation.
bazel test //...
bazel run //:exampleThe CI matrix covers Bazel 8 and 9 on Linux, macOS, and Windows.
The API and implementation are new, but the fixed-reference and SelfBLEU use cases are based on Danial Alihosseini's fast-bleu project and its associated paper, Jointly Measuring Diversity and Quality in Text Generation Models. See THIRD_PARTY_NOTICES.md.
MIT