Skip to content

[STIM] Finalize non-Clifford support - #3647

Open
João Boechat (joao-boechat) wants to merge 12 commits into
mainfrom
joaoboechat/finalize-non-clifford-support
Open

[STIM] Finalize non-Clifford support#3647
João Boechat (joao-boechat) wants to merge 12 commits into
mainfrom
joaoboechat/finalize-non-clifford-support

Conversation

@joao-boechat

@joao-boechat João Boechat (joao-boechat) commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

This PR finalizes non-Clifford support in the STIM-to-QIR pipeline by adding the remaining gate lowerings, explicit radian angles, and CCX execution in the Clifford simulator.

STIM compiler

  • Adds QIR lowering for TPP/TPP_DAG, CH, CCX, CCZ, U/U3, R_XX/R_YY/R_ZZ, and R_PAULI.
  • Splits number scanning into integer, fraction, exponent, and rad suffix helpers, making the lexer easier to follow.
  • Makes Double tokens unit-aware through DoubleUnit, distinguishing default values from radians before parsing.
  • Represents parsed arguments as Arg { value, span }, preserving their units and source locations for compiler validation.
  • Centralizes double extraction, strips the rad suffix before conversion, and reports floating-point overflow at the argument span.
  • Converts default angles from half turns to radians, passes explicit radians through unchanged, and rejects radians for probability arguments.
  • Improves argument-count errors by reporting the expected and actual counts for too few or too many arguments.
  • Reorders compiler helpers by purpose, making argument validation, target broadcasting, and QIR emission easier to navigate.
  • Handles broadcasting and validation for single-, pair-, triple-, and Pauli-product targets, including negated Pauli products.

Sample notebooks

  • Consolidated all of the three stim notebooks we had into one: qdk_stim.ipynb.

Tests

  • Covers number parsing, radian units, overflow, gate lowering, broadcasting, argument counts, and invalid targets.

Simulation

  • Decomposes CCX into Clifford+T operations so CCX circuits can run in the Clifford simulator.

Editor support

  • Highlights the new gates and rad-suffixed numbers in STIM files.

Comment thread source/compiler/stim_compiler/src/lex.rs
}

#[test]
fn pauli_channel_1_with_probability_in_radians_yields_error() {

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.

Could you add a test where more than one argument is expressed in radians? Should multiple errors surface, or will it just be one error for the whole call?

}

#[test]
fn peek_loss_with_readout_noise_in_radians_yields_error() {

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.

What about a test for an argument -0.1rad? That way we can test for both errors surfacing instead of one "beating" the other.

args:
Arg [2-6]:
value: 0.01

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.

Can we avoid having this extra line space here? It breaks off the "targets" field and makes it look like it is unrelated to the rest of the fields of Instruction.


impl Display for Arg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln_header_with_span(f, "Arg", self.span)?;

@ScottCarda-MS Scott Carda (ScottCarda-MS) Aug 27, 2026

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.

The value field is pretty compact in its display. Consider making the Arg display a single line:
Arg [x-y]: 1.2 rad

impl Display for Arg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln_header_with_span(f, "Arg", self.span)?;
writeln_field(f, "value", &self.value)

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.

Suggested change
writeln_field(f, "value", &self.value)
write_field(f, "value", &self.value)

I think using write_field like Target does will avoid that extra line space in the output.

"source": [
"## Controlled gates\n",
"\n",
"`CH` applies a Hadamard when its control is `1`. `CCX` flips its target, and `CCZ` applies a phase flip, when both controls are `1`."

@ScottCarda-MS Scott Carda (ScottCarda-MS) Aug 27, 2026

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.

It is a bit more nuanced than this makes it sound. How deep you want to describe this depends on the audience, but doing a quantum operation with a control means that the execution of the operation is entangled to the part of the quantum state of the control that is 1. There's probably a better way to word that then what I gave, but I assume there are nice descriptions of what quantum controls do out there.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I have merged all of the stim notebooks into a single, more complete one. The idea isn't for it to be a full documentation of how all of the gates are supposed to work. For that, one can simply go to stim's docs. For now, this is supposed to be used by people who already use stim / clifft but aren't familiar with qdk.stim.

In this particular case, the description is explaining what the example is supposed to do, rather than making a general statement about those gates.

@domorale

Copy link
Copy Markdown

The non-Clifford gate support and lowerings look good. I have one blocking design concern: could we use half turns exclusively and remove the rad syntax?

This matches Clifft’s model, including U3/U, and avoids introducing a QDK-specific extension to Stim’s plain-double grammar.

Concretely:

  • Remove rad and mixed-unit support from the lexer, parser, diagnostics, tests, syntax highlighting, notebook, and PR description.
  • Represent arguments as Arg { span, value: f64 }, keeping source locations without embedding unit policy in the AST.
  • Let each instruction interpret its arguments and convert rotation angles from half turns to radians at the QIR lowering boundary.
  • Preserve tests distinguishing Stim’s RX reset from the R_X(...) rotation.

This also removes duplicated unit semantics across the lexer, AST, and validators, leaving one instruction-owned interpretation point.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Requesting changes based on the angle-unit design concern in my review comment. I consider this a user-facing compatibility and predictability issue: matching Clifft’s half-turn model avoids a QDK-specific Stim dialect.

@joao-boechat

Copy link
Copy Markdown
Contributor Author

Domingo Morales Lizama (@domorale), answering your comment: we decided to add the rad suffix after discussing it within the team and with the QEC researchers, mainly for two reasons:

  1. Radians are useful for some specific QEC algorithms and make qdk-stim more accessible to other domains, such as chemistry, where angles are typically expressed in radians rather than half-turns.
  2. This is an opt-in extension that preserves standard Stim behavior. Half-turns remain the default, so standard Stim/Clifft programs continue to work unchanged. Users can explicitly use rad when needed, with documentation making it clear that this syntax is specific to qdk-stim and is not portable back to Stim/Clifft.
    We’re also already extending the Stim grammar in other areas where needed, such as using L to represent loss, so this wouldn't be the first time we do that.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I requested changes earlier, but the discussion about opt-in rad support and compatibility clarified the design intent. I approve the approach.

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