Skip to content

feat(gates): add RotXY in-plane single-qubit rotation (R gate)#170

Merged
david-pl merged 1 commit into
mainfrom
feat/single-qubit-rotations
Jul 8, 2026
Merged

feat(gates): add RotXY in-plane single-qubit rotation (R gate)#170
david-pl merged 1 commit into
mainfrom
feat/single-qubit-rotations

Conversation

@david-pl

@david-pl david-pl commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Merge order

Part of splitting #168 into small, focused PRs. Full stack (independent items may merge in any relative order; dependents wait for their base):

  1. single-qubit rotations (this PR)main
  2. core tableau expectation/reset (feat/tableau-expectation-reset) → main
  3. native .pyi type stubs (feat/native-pyi-stubs) → this PR (declares the native r added here)
  4. vihaco-circuit-isa (feat(vihaco-circuit-isa): add standalone circuit ISA crate #169) → main
  5. circuit component (david/42.2-circuit-component) → feat(vihaco-circuit-isa): add standalone circuit ISA crate #169
  6. composite (david/42.3-composite) → PauliSum printing should properly display small floating points #5
  7. CLI + TUI (Add a composable ratatui TUI to ppvm-cli #166) → Trotter circuit simulation #6

Items 1, 2, and 4 are mutually independent off main.

Summary

Adds the RotXY trait to ppvm-traits and implements it for both backends (ppvm-tableau, ppvm-pauli-sum), plus the r(...) Python binding on the native PauliSum / tableau classes and the RotationsMixin / TruncatingRotationsMixin wrappers.

RotXY is a single-qubit rotation about an arbitrary axis in the X/Y plane:

R(axis_angle, θ) = exp(-i θ/2 · (cos(axis_angle)·X + sin(axis_angle)·Y))
                 = RZ(axis_angle)·RX(θ)·RZ(−axis_angle)

Pure addition alongside the existing RotationOne (RX/RY/RZ) rotations; no new module wiring. Like u3, r is single-qubit (scalar addr0), not batched over targets.

Provenance

Snapshotted from the tip of #168 (not cherry-picked); the R gate is a prerequisite for the circuit-component backends there.

Testing

cargo test -p ppvm-traits -p ppvm-tableau -p ppvm-pauli-sum green (incl. test_rx/ry/rz/r). Python: maturin develop + pytest test/test_basics.py test/generalized_tableau/test_basics.py → 37 passed. prek hooks (fmt, check, clippy, machete, ruff, ty, license) all pass.

Add the `RotXY` trait to `ppvm-traits` and implement it for both
backends (`ppvm-tableau`, `ppvm-pauli-sum`), plus the `r(...)` Python
binding on the native PauliSum / tableau classes and the
`RotationsMixin` / `TruncatingRotationsMixin` wrappers.

`RotXY` is a single-qubit rotation about an arbitrary axis in the X/Y
plane:

    R(axis_angle, θ) = exp(-i θ/2 · (cos(axis_angle)·X + sin(axis_angle)·Y))
                     = RZ(axis_angle)·RX(θ)·RZ(−axis_angle)

Pure addition alongside the existing `RotationOne` (RX/RY/RZ) rotations;
no new module wiring. Native type stubs (`.pyi`) for the whole module
are split into a separate follow-up PR. Snapshotted from #168, where the
R gate is a prerequisite for the circuit-component backends.

Merge order for the #168 split: single-qubit rotations (this) and core
tableau expectation/reset target `main` independently; native .pyi stubs
stack on this; then vihaco-circuit-isa (#169) -> circuit component ->
composite -> CLI/TUI (#166).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-07-08 09:06 UTC

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

Adds support for an in-plane single-qubit rotation gate R(axis_angle, θ) across the Rust trait layer, both simulation backends (tableau + PauliSum), and the Python API surface, including targeted regression tests to ensure the intended Heisenberg/Schrödinger ordering semantics.

Changes:

  • Introduces the RotXY trait in ppvm-traits and re-exports it for downstream consumers.
  • Implements RotXY::r for GeneralizedTableau (Schrödinger picture via RZ(-φ) → RX(θ) → RZ(φ)) and for PauliSum (Heisenberg picture ordering).
  • Exposes r(...) in the native Python bindings and Python mixins, and adds Rust + Python tests validating key identities (e.g., axis_angle=0 => RX, axis_angle=π/2 => RY).

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
ppvm-python/test/test_basics.py Adds PauliSum-level Python tests for r(...) matching rx/ry special cases.
ppvm-python/test/generalized_tableau/test_basics.py Adds GeneralizedTableau Python tests confirming r(...) reduces to rx/ry at key axis angles.
ppvm-python/src/ppvm/mixins.py Adds r(...) to RotationsMixin and TruncatingRotationsMixin with docstring math and truncation support.
crates/ppvm-traits/src/traits/mod.rs Re-exports RotXY from the traits prelude.
crates/ppvm-traits/src/traits/branch/rot1.rs Defines the new RotXY trait and documents the RZ(φ) RX(θ) RZ(-φ) decomposition.
crates/ppvm-traits/src/traits/branch/mod.rs Re-exports RotXY from the branch module.
crates/ppvm-tableau/src/gates/rot1.rs Implements RotXY for GeneralizedTableau and adds backend-level tests for identity/special cases/statistics equivalence.
crates/ppvm-python-native/src/interface.rs Adds native PauliSum binding r(addr0, axis_angle, theta, truncate=True).
crates/ppvm-python-native/src/interface_tableau.rs Adds native tableau binding r(addr0, axis_angle, theta).
crates/ppvm-pauli-sum/src/sum/rot1.rs Implements RotXY for PauliSum and adds a test guarding the Heisenberg-order sign convention.

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

@david-pl david-pl merged commit 6dacadf into main Jul 8, 2026
15 checks passed
@david-pl david-pl deleted the feat/single-qubit-rotations branch July 8, 2026 09:06
david-pl added a commit that referenced this pull request Jul 8, 2026
## Merge order

Part of splitting #168 into small, focused PRs. Full stack (independent
items may merge in any relative order; dependents wait for their base):

1. single-qubit rotations (#170) → `main`
2. **core tableau expectation/reset (this PR)** → `main`
3. native `.pyi` type stubs (`feat/native-pyi-stubs`) → #170
4. vihaco-circuit-isa (#169) → `main`
5. circuit component (`david/42.2-circuit-component`) → #169
6. composite (`david/42.3-composite`) → #5
7. CLI + TUI (#166) → #6

Items 1, 2, and 4 are mutually independent off `main`.

## Summary

Adds `expectation.rs` for `GeneralizedTableau`:
- `expectation` — single-Pauli ⟨ψ|P|ψ⟩ for a `PauliWord`, conjugating P
through the tableau and overlapping with the sparse coefficient vector.
- `trace` — Σ over Paulis matching a `PauliPattern`.

Supporting changes in `data.rs`:
- `compute_decomposition_word` — multi-qubit conjugation used by
`expectation`.
- `reset_all` on both `Tableau` and `GeneralizedTableau` — reinitialise
to |0…0⟩, clearing coefficients and loss state (refactors `new` via a
shared `new_data` helper).
- the rayon-nesting guard on the coefficient path (avoids nesting rayon
inside shot-level parallelism; a no-op on the single-shot path).

`lib.rs` gains `pub mod expectation`; `Cargo.toml` gains a
`ppvm-pauli-word` dependency. Pure core addition, snapshotted from #168.

## Testing

`cargo test -p ppvm-tableau` green (12 expectation tests + reset/noise).
prek hooks all pass.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
david-pl added a commit that referenced this pull request Jul 8, 2026
## Merge order

Part of the #168 split. **Stacked on #170** (base branch
`feat/single-qubit-rotations`) because this stub file declares the
native `r` binding that #170 adds. Merge #170 first, then this.

Full stack: single-qubit rotations (#170) → **this** ; core tableau
expectation/reset (`feat/tableau-expectation-reset`) → `main` ;
vihaco-circuit-isa (#169) → `main` ; then circuit component → composite
→ CLI/TUI (#166).

## Summary

Adds `ppvm_python_native.pyi` — the first type-stub file for the
compiled `ppvm._core` module (none exists on `main`). It declares the
macro-generated concrete classes (`PauliSumIndexMapFxHash{0..15}`,
`PauliSumLossIndexMapFxHash{0..15}`, the `GeneralizedTableau{N}` family,
`StimProgram`) via synthetic `_PauliSumBase` / `_PauliSumLossBase` /
`_GeneralizedTableauBase` bases that hold the shared method signatures
once.

Pure additive typing surface; no runtime effect. Split out of #170
because the block covers the whole module — only `r` is new API; the
rest describe pre-existing bindings.

## Provenance

Snapshotted from the tip of #168.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Roger-luo added a commit that referenced this pull request Jul 13, 2026
## Merge order

Part of the #168 split. This PR targets **#169**
(`david/42.1-vihaco-isa`), not `main`, and stacks on the core
prerequisites:

1. RotXY / R gate (#170) → `main` ✅ merged
2. tableau expectation/reset (#172) → `main` ✅ merged
3. vihaco-circuit-isa (#169) → `main` (open; has `main` merged in, so it
carries #170 + #172)
4. native `.pyi` stubs (#171) → `main` (open; independent of this line)
5. **circuit component (this PR)** → #169
6. composite (`david/42.3-composite`) → this PR
7. CLI + TUI (#166) → #6

## Summary

Introduces the `ppvm-vihaco` crate with just the **circuit component**
slice — the piece that dispatches gates to a backend. The composite
machine that drives it (VM, bytecode, syntax, shots) is the next PR.

| File | What |
|------|------|
| `component.rs` | `Circuit` — dispatches `CircuitInstruction`s to a
tableau / PauliSum / lossy-PauliSum backend, emitting measurement +
trace effects (incl. the R gate and trace/reset, now that #170/#172 are
in `main`) |
| `measurements.rs` | measurement / trace effect + observer types |
| `device_info.rs` | `PPVM_MAGIC`, `BackendKind`, `PPVMDeviceInfo` —
**relocated** out of the composite so the component compiles standalone;
the composite PR imports them from here |
| `lib.rs` | component-only module wiring; composite-driven
`load`/`run`/`dump`/`parse` helpers come with the composite |

## Notes

- **`device_info.rs`**: the whole `PPVM_MAGIC` + `BackendKind` +
`PPVMDeviceInfo` cluster moved (the struct can't compile without the
other two). In #5, `composite.rs` imports these instead of defining
them.
- **machete ignore** for `chumsky` + `vihaco-parser-core` — pulled in
only via the `vihaco_parser::Parse` derive on `BackendKind` (mirrors the
isa crate).

## Testing

`cargo test -p ppvm-vihaco` — 2 smoke tests (single-qubit flip + CNOT
propagation through the component's dispatch). Fuller integration
coverage arrives with the composite's `.sst` fixtures. Full workspace
builds; clippy + machete clean.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Xiu-zhe (Roger) Luo <rluo@quera.com>
david-pl added a commit that referenced this pull request Jul 14, 2026
## Merge order

Part of the #168 split. This PR targets **#173**
(`david/42.2-circuit-component`) and sits at the top of the vihaco line:

1. RotXY / R gate (#170) → `main` ✅ merged
2. tableau expectation/reset (#172) → `main` ✅ merged
3. vihaco-circuit-isa (#169) → `main` (open; carries #170 + #172 via a
`main` merge)
4. native `.pyi` stubs (#171) → `main` (open; independent)
5. circuit component (#173) → #169
6. **composite machine + VM (this PR)** → #173
7. CLI + TUI (#166) → this PR

## Summary

Completes the `ppvm-vihaco` crate on top of the circuit component (#173)
— the composite machine that drives it plus the surrounding VM.

| File | What |
|------|------|
| `composite.rs` | the `PPVM` composite: vihaco machine (CPU + program
loader) driving the circuit component, measurement/trace observers,
backend selection from the device header, reset, single-instruction
stepping |
| `syntax.rs` | `.sst` header parse / lower (`PPVMHeader`,
`PPVMResolver`) |
| `bytecode.rs` | `.ssb` bytecode emit / load (magic-tagged) |
| `observable.rs` | observable-header parsing for the PauliSum backends
|
| `shots.rs` | multi-shot execution (serial + optional `rayon`) |
| `lib.rs` | full module wiring + `load`/`run`/`dump`/`compile`/`parse`
helpers + `PPVMModule` |
| `Cargo.toml` | adds `vihaco-cpu`, `log`, optional `rayon` feature |
| `tests/*.sst` + `sst_fixtures.rs` | 28 integration fixtures |

## `device_info` relocation resolves here

`composite.rs` no longer defines `PPVM_MAGIC` / `BackendKind` /
`PPVMDeviceInfo` — it imports them from `device_info` (introduced in
#173) and `pub use`-re-exports them, so the existing
`crate::composite::{…}` paths in `lib.rs` / `bytecode.rs` / `syntax.rs`
keep resolving with no other edits.

The machete-ignore added in #173 is dropped here — the full crate uses
`chumsky` / `vihaco-parser-core` directly.

## Testing

`cargo test -p ppvm-vihaco` — **111 unit + 28 integration** tests, green
with and without `--features rayon`. Full workspace builds; clippy +
machete clean.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
david-pl added a commit that referenced this pull request Jul 14, 2026
## Merge order

Part of the #168 split. This PR targets **#174**
(`david/42.3-composite`) and adds the CLI binary the TUI PR builds on:

1. RotXY / R gate (#170) → `main` ✅ merged
2. tableau expectation/reset (#172) → `main` ✅ merged
3. vihaco-circuit-isa (#169) → `main` (open)
4. native `.pyi` stubs (#171) → `main` (open; independent)
5. circuit component (#173) → #169
6. composite machine + VM (#174) → #173
7. **ppvm-cli binary (this PR)** → #174
8. ratatui TUI (#166) → this PR

## Summary

Extracts the `ppvm-cli` crate — the `ppvm` binary — from #168 onto the
composite. This is the **base CLI without the TUI**: clap-based `run` /
`dump` / `parse` / `debug` subcommands over `ppvm-vihaco`, plus example
`.sst` programs. The ratatui TUI that layers on top of it is the
follow-up PR (#166), which modifies this crate.

`ppvm-cli` was part of #168's implementation but had no extraction step
of its own — the original split plan conflated it with the TUI PR. It
slots in here between the composite and the TUI.

- Depends on `ppvm-vihaco` (with `rayon`), `clap`, `eyre`.
- **Excluded from the wasm32 CI build** (terminal binary, forces
`rayon`), mirroring #168's exclusion — `ppvm-vihaco` itself still builds
for wasm, so only `ppvm-cli` is excluded; the reusable engine stays
covered.

## Testing

`cargo test -p ppvm-cli` — 23 pass. `ppvm run examples/ghz.sst` runs.
clippy + machete clean; full workspace builds; `ppvm-vihaco` still
builds for `wasm32-unknown-unknown`.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@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.

2 participants