Skip to content

Add EBNF and Lark sampling temperature support - #730

Merged
Seven-Streams merged 7 commits into
mlc-ai:mainfrom
Ubospica:feat/lark-temperature
Jul 28, 2026
Merged

Seven-Streams merged 7 commits into
mlc-ai:mainfrom
Ubospica:feat/lark-temperature

Conversation

@Ubospica

@Ubospica Ubospica commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add [temperature=VALUE] attributes for Lark terminals and subgrammars, including nested override and ambiguous-path handling
  • expose effective temperatures through GrammarMatcher, BatchGrammarMatcher, and draft-tree traversal APIs
  • preserve temperature metadata through grammar transformations and serialization, with documentation and 28 focused Python tests

Test plan

  • pre-commit run --all-files
  • ruff check python/xgrammar/matcher.py tests/python/test_temperature.py tests/python/test_serialization.py
  • HF_HUB_OFFLINE=1 TRANSFORMERS_OFFLINE=1 pytest -q tests/python/test_temperature.py tests/python/test_lark.py tests/python/test_grammar_matcher_basic.py tests/python/test_speculative_decoding.py tests/python/test_serialization.py tests/python/test_grammar_parser.py (349 passed)

@Ubospica
Ubospica requested a review from Seven-Streams as a code owner July 23, 2026 09:35
Copilot AI review requested due to automatic review settings July 23, 2026 09:35
@Ubospica
Ubospica requested a review from DarkSharpness as a code owner July 23, 2026 09:35

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 adds end-to-end support for rule-scoped sampling temperatures in Lark grammars, surfaces the effective temperature through matcher APIs (single, batch, and speculative draft-tree traversal), and preserves the metadata through grammar transformations, printing/parsing, and JSON serialization.

Changes:

  • Add [temperature=VALUE] attributes for eligible Lark rules/subgrammars and propagate “active temperature” through the Earley parsing state.
  • Expose effective temperatures via GrammarMatcher.temperature, return temperatures from BatchGrammarMatcher.batch_fill_next_token_bitmask, and optionally fill per-node temperatures in GrammarMatcher.traverse_draft_tree.
  • Persist temperature through grammar transforms + EBNF printing/parsing + JSON serialization, with new docs and focused Python tests.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/python/test_temperature.py Adds focused tests for default/override/ambiguity behavior, batch API return values, traversal temperature filling, and validation.
tests/python/test_serialization.py Updates expected serialized rules shape to include the new temperature field.
python/xgrammar/matcher.py Adds default_temperature, temperature property, traversal temperatures output tensor, and batch API return value.
include/xgrammar/matcher.h Extends C++ matcher APIs with default_temperature, GetTemperature, traversal temperatures, and batch-return temperatures.
docs/defining_structures/lark_grammar.md Documents %json/%lark and adds new “Sampling Temperature” rule option documentation.
cpp/tvm_ffi/tvm_ffi.cc Adds optional-float marshaling, threads temperature data through FFI, and returns temperatures from batch bitmask fill.
cpp/lark_converter.cc Parses temperature rule attributes, restricts applicability, and persists per-rule temperature into the grammar builder.
cpp/grammar_printer.cc Prints [temperature=...] on rules with temperature, using a precise float representation.
cpp/grammar_parser.h Adds FloatLiteral token type to support parsing printed temperatures.
cpp/grammar_parser.cc Extends lexer/parser to read rule attributes and float literals; persists parsed temperature into the builder.
cpp/grammar_matcher.cc Stores default_temperature, tracks active_temperature_rule_id through parsing, computes max temperature across ambiguous scan states, returns temperatures from batch fill, and fills traversal temperatures.
cpp/grammar_impl.h Adds temperature to rule metadata and includes it in reflection-based serialization.
cpp/grammar_functor.h Preserves rule temperature during grammar functor transformations.
cpp/grammar_functor.cc Preserves rule temperature across multiple grammar mutators/transformers and avoids inlining/optimizations that would lose it.
cpp/grammar_builder.h Adds UpdateRuleTemperature API.
cpp/grammar_builder.cc Implements UpdateRuleTemperature.
cpp/earley_parser.h Adds active_temperature_rule_id to parser state and introduces resolver for inherited temperature.
cpp/earley_parser.cc Propagates active_temperature_rule_id through rule expansion/completion/prediction to support correct runtime temperature reporting.

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

Comment thread python/xgrammar/matcher.py Outdated
Comment on lines +391 to +394
temperatures : Optional[torch.Tensor], default: None
Optional 1D float32 CPU tensor with one element per node. It is filled with the
effective temperature for each visited node. ``NaN`` means that no temperature
is configured.
Comment thread include/xgrammar/matcher.h Outdated
Comment on lines +133 to +134
* \param temperatures Optional DLTensor to store the effective temperature for each node
* (1D float32 with num_nodes elements). NaN represents no effective temperature.
Comment thread tests/python/test_serialization.py Outdated
serialized = grammar.serialize_json()
expected_json = {
"rules": [["rule1", 4, -1, False], ["root", 8, -1, False]],
"rules": [["rule1", 4, -1, False, None], ["root", 8, -1, False, None]],
@Ubospica Ubospica changed the title Add Lark sampling temperature support Add EBNF and Lark sampling temperature support Jul 23, 2026
Ubospica added 7 commits July 26, 2026 15:48
Propagate rule-level sampling temperatures through matching so single, batched, and speculative decoding callers can apply the effective value.
Group embedded grammar directives with the other directives and present their examples directly as Lark source.
Make ambiguous temperature selection visible while retaining LLGuidance-compatible maximum-value behavior without repeated warnings.
Keep batch bitmask filling focused on mask generation and expose temperatures through an explicit batch query without repeated Python-to-C++ calls.
Expose the native EBNF rule-option syntax and cover its runtime behavior and validation directly in Python tests.
Rely on the built-in standard-library type traits for optional temperatures and batch results, removing manual Any conversion helpers.
@Ubospica
Ubospica force-pushed the feat/lark-temperature branch from 01e8dbc to a186cc6 Compare July 26, 2026 20:28
@Seven-Streams
Seven-Streams merged commit e35709f into mlc-ai:main Jul 28, 2026
47 checks passed
@cjackal

cjackal commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Hi, I think the std::optional<float> type does not convert correctly to Optional[float] on xgrammar-python side in tvm_ffi.cc - on latest main one get a SyntaxError at import time like:

...
  def __c_ffi_init__(_0: Object, _1: Any, _2: bool, _3: int, _4: std::optional[float], /) -> Object: ...

Seven-Streams pushed a commit that referenced this pull request Aug 5, 2026
Fix #756. 

The root cause of the syntax error is that `apache-tvm-ffi<=0.1.9` does
not correctly convert the `std::optional<T>` types (newly added in
temperature support #730) into python `Optional[T]` type hints. The type
mapping issue was fixed in `apache-tvm-ffi==0.1.10`.

Signed-off-by: cjackal <44624812+cjackal@users.noreply.github.com>
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.

4 participants