Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions crates/ppvm-stim/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,11 @@ pub fn execute_validated<T, I, C>(
GateName::T | GateName::TDag => {
unreachable!("T/T_DAG are lowered to ExtendedInstruction::T/TDag by interpret")
}
GateName::RotX | GateName::RotY | GateName::RotZ | GateName::U3 => {
unreachable!(
"R_X/R_Y/R_Z/U3 are lowered to ExtendedInstruction::Rotation/U3 by the parser"
)
}
},
ExtendedInstruction::T { targets, .. } => targets.iter().for_each(|&q| tab.t(q)),
ExtendedInstruction::TDag { targets, .. } => {
Expand Down
4 changes: 2 additions & 2 deletions crates/ppvm-stim/src/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ fn check_gate_supported(name: GateName, line: usize) -> Result<(), ExecError> {
use GateName::*;
match name {
Reset | ResetZ | ResetX | ResetY | X | Y | Z | H | HXZ | S | SqrtZ | SDag | SqrtZDag
| SqrtX | SqrtXDag | SqrtY | SqrtYDag | T | TDag | Identity | CX | ZCX | CNot | CY
| ZCY | CZ | ZCZ => Ok(()),
| SqrtX | SqrtXDag | SqrtY | SqrtYDag | T | TDag | Identity | RotX | RotY | RotZ | U3
| CX | ZCX | CNot | CY | ZCY | CZ | ZCZ => Ok(()),
Swap | ISwap | ISwapDag | SqrtXX | SqrtYY | SqrtZZ | CXSwap | SwapCX | XCX | XCY | XCZ
| YCX | YCY | YCZ | CXYZ | CZYX | HXY | HYZ => Err(ExecError::Unsupported {
name: name.canonical_name().to_string(),
Expand Down
20 changes: 19 additions & 1 deletion crates/ppvm-stim/tests/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,28 @@ fn rx_pi_flips_qubit() {

#[test]
fn u3_pi_flip_via_y_axis() {
let (results, _) = run("I[U3(theta=1.0*pi, phi=0.0, lambda=0.0)] 0\nM 0", 1);
let (results, _) = run("I[U3(theta=1.0*pi, phi=0.0*pi, lambda=0.0*pi)] 0\nM 0", 1);
assert_eq!(results, vec![Some(true)]);
}

#[test]
fn u3_all_angles_nonzero_exercises_phi_lambda() {
// U3(theta=pi, phi=pi/2, lambda=pi/2) == Y (clifft Rz(phi)Ry(theta)Rz(lambda)),
// so H·U3·H == H·Y·H == -Y and |0> -> |1> deterministically. The H frame makes
// the outcome sensitive to phi *and* lambda (drop or mis-scale either and P(1)
// collapses to ~0.5). Half-turn args 1.0/0.5/0.5 each get *pi at lowering.
let tag = run(
"H 0\nI[U3(theta=1.0*pi, phi=0.5*pi, lambda=0.5*pi)] 0\nH 0\nM 0",
1,
);
assert_eq!(tag.0, vec![Some(true)]);

// Bare half-turn form must agree; this also pins the `* pi` scaling (an
// unscaled bare U3 would read 1.0/0.5/0.5 as radians and P(1) drops to ~0.4).
let bare = run("H 0\nU3(1.0, 0.5, 0.5) 0\nH 0\nM 0", 1);
assert_eq!(bare.0, vec![Some(true)]);
}

#[test]
fn t_gate_via_s_t_tag_no_op_on_zero() {
let (results, _) = run("S[T] 0\nM 0", 1);
Expand Down
9 changes: 8 additions & 1 deletion crates/stim-parser/src/ast/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,14 @@ pub struct Tag {
#[derive(Debug, Clone, PartialEq)]
pub enum TagParam {
Positional(f64),
Named { key: String, value: f64 },
/// A `key=value` tag parameter. `had_pi` records whether the value was
/// written as a `<n>*pi` (or bare `pi`) expression — rotation/U3 tags
/// require it (half-turn convention), and the printer re-emits `*pi`.
Named {
key: String,
value: f64,
had_pi: bool,
},
}

/// The rotation axis for an extended-dialect `R_X` / `R_Y` / `R_Z` rotation.
Expand Down
11 changes: 11 additions & 0 deletions crates/stim-parser/src/instructions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ pub enum GateName {
TDag,
// Identity (carries dialect tags like S[T] is on S, but I[R_X(...)] is on Identity)
Identity,
// Parameterized single-qubit rotations / U3 (continuous angle in half-turns,
// clifft/tsim dialect; also expressible as I[R_X(theta=..*pi)] / I[U3(...)])
RotX,
RotY,
RotZ,
U3,
// Two-qubit Cliffords
CX,
ZCX,
Expand Down Expand Up @@ -258,6 +264,11 @@ const TABLE: &[(&str, TableEntry)] = &[
("T", gate(G::T, NoArgs, AtLeastOne, "T")),
("T_DAG", gate(G::TDag, NoArgs, AtLeastOne, "T_DAG")),
("I", gate(G::Identity, NoArgs, AtLeastOne, "I")),
// --- Gates: parameterized rotations (angle in half-turns) ---
("R_X", gate(G::RotX, Exact(1), AtLeastOne, "R_X")),
("R_Y", gate(G::RotY, Exact(1), AtLeastOne, "R_Y")),
("R_Z", gate(G::RotZ, Exact(1), AtLeastOne, "R_Z")),
("U3", gate(G::U3, Exact(3), AtLeastOne, "U3")),
// --- Gates: two-qubit Clifford ---
("CX", gate(G::CX, NoArgs, Pairs, "CX")),
("ZCX", gate(G::ZCX, NoArgs, Pairs, "ZCX")),
Expand Down
Loading
Loading