Skip to content

Add exact Clifford-to-Pauli-exponent decomposition - #116

Open
Marcus P S (marcusps) wants to merge 54 commits into
microsoft:mainfrom
marcusps:masilv/clifford-pauli-exp-decomp
Open

Add exact Clifford-to-Pauli-exponent decomposition#116
Marcus P S (marcusps) wants to merge 54 commits into
microsoft:mainfrom
marcusps:masilv/clifford-pauli-exp-decomp

Conversation

@marcusps

Copy link
Copy Markdown
Contributor

Summary

  • Adds an exact, sign-preserving O(n²) decomposition of a Clifford into π/4 Pauli exponents.
  • Replaying the factors reconstructs the full signed tableau, not only its symplectic action.
  • Adds Rust/Python APIs, round-trip tests, and documentation.

Published reference

This decomposition is the phase-exact building block used by §4.3 of Phased outcome-complete simulation (arXiv:2603.24717): Clifford factors are decomposed and replayed while tracking their ζ₈ phase.

Review series

This is the second of three dependent PRs. It is stacked on #115 and should be reviewed and merged after it. Until #115 merges and this branch is rebased, GitHub shows the preceding PR’s commits as part of this draft; the new review scope is the Clifford decomposition, its bindings, tests, and documentation.

Marcus P S (marcusps) and others added 25 commits June 14, 2026 04:21
Implement the global-phase-tracking generalization of outcome-complete
stabilizer simulation (KBP, arXiv:2309.08676 Alg. 5.3), following the
phased-simulation algorithm of arXiv:2603.24717.

paulimer:
- New `PhasedCliffordUnitary` primitive (clifford/phased_clifford.rs): a
  `CliffordUnitary` plus an exact global-phase tracker for the encoder state
  `Co|0…0>`, with phase-aware left-multiplication of elementary generators,
  Pauli, Pauli-exp and Clifford, and an exact stabilizer-amplitude helper.
  Global phases are tracked entirely as exact integer ζ₈ exponents (mod 8):
  amplitude sums reduce to pure integer logic (separations d ∈ {0,2,6}, or
  cancellation at d = 4), with no floating-point or complex arithmetic.
- Dense statevector validation harness (tests/phased_clifford_dense.rs).

pauliverse:
- New `PhasedOutcomeCompleteSimulation` implementing the `Simulation` trait,
  mirroring `OutcomeCompleteSimulation` and additionally tracking the
  quadratic phase matrix B and the linear i/-1 phase vectors p, s, so the
  output state is i^<p,r> (-1)^<Br+s,r> R|Ar>.
- Exhaustive dense-statevector test enumerating every random-bit assignment r
  and comparing phase-exactly against a brute-force reference
  (tests/phased_outcome_complete_dense.rs).

Python bindings:
- `PhasedOutcomeCompleteSimulation` exposed through paulimer/bindings/python,
  with phase accessors (sign/quadratic-phase/outcome matrices, outcome shift,
  linear i/-1 phase vectors, output_phase_exponent), .pyi stubs and tests.

Docs: pauliverse crate docs and README updated to a fifth simulation mode,
citing arXiv:2603.24717.

The §4.5 auxiliary-qubit separation and §4.1 verification application are
deferred as follow-ups.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Demonstrates `PhasedOutcomeCompleteSimulation` (arXiv:2603.24717) using only the
exposed phase data — no state vector is ever formed. Prepares |++>, measures Y on
each qubit, and shows the four branch phases 1, i, i, -1, where the two i factors
interfere to -1 (captured exactly by the quadratic phase matrix B since the linear
i-phase p is tracked mod 2). Reconstructs the zeta8 exponent from A, B, p, s with
exact integer arithmetic and asserts it against output_phase_exponent, contrasts
with the phaseless OutcomeCompleteSimulation, and explains the §4.1 verification
application.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Demonstrates applying a symbolic rotation exp(iαP) to PhasedOutcomeCompleteSimulation
by conditioning the Pauli P on a fresh allocate_random_bit(), following §4.1 of
arXiv:2603.24717. Shows the two branches (cos α / i·sin α weights), verifies that
H·exp(iαZ)·H and exp(iαX) have identical exact phase signatures, and catches a buggy
exp(iαY) variant that the phaseless OutcomeCompleteSimulation cannot distinguish from
exp(iαX) (the two differ only by a relative branch phase). Statevector-free and
self-verifying via asserts; executed with outputs committed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…ython

Augments the circuit-action machinery with an exact-global-phase analog of
`action_of`/`CircuitAction` for verifying symbolic-rotation circuits as
operators (Choi states / channel-state duality).

- pauliverse: refactor `build_action` to share a post-simulation
  `action_from_simulation` core; add `phased_action_of` (Circuit path),
  `phased_action_from_simulation` (simulator-native path), and
  `PhasedCircuitAction` with `is_equivalent` / `is_equivalent_up_to_signs`.
  Equality is up to a single global phase; relative branch phases (which
  distinguish e.g. e^{+iaZ} from e^{-iaZ}) are compared via the degree-<=2
  phase polynomial phi(r) = 2<p,r> + 4<Br+s,r> mod 8.
- bindings: expose `PhasedOutcomeCompleteSimulation.phased_action(...)` and
  the `PhasedCircuitAction` class; update the `.pyi` stub and `__all__`.
- tests: Rust `phased_action_test.rs` (Circuit + simulator-native paths) and
  Python `TestPhasedCircuitAction`.
- example: rewrite `verifying-symbolic-rotations.ipynb` to use the principled
  `phased_action` API instead of raw-field comparison.

Each random bit is currently treated as a symbolic rotation angle matched
one-to-one between circuits; distinguishing virtual angle bits from true
measurement randomness (affine remapping) is a tracked follow-up.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…d actions

Introduce a first-class `allocate_symbolic_angle()` allocation that tags a
random bit as a *virtual* rotation angle, distinct from a *true* measurement
random bit. The phased Choi-action equivalence now enforces the distinction:
symbolic angles must correspond one-to-one (in allocation order) between two
compared circuits, while true measurement bits may be marginalized/affinely
remapped. The two kinds are never mixed (guarded by SymbolicAngleCount /
SymbolicAngleMixed inequivalence reasons).

Core fix: `relative_phase_matches` now compares the degree-<=2 branch-phase
polynomial only over the symbolic-angle bits (true bits zeroed). Symbolic
angles model coherent `e^{i a P}` superpositions whose relative phase is
observable; true measurement bits label incoherent, traced-out branches whose
per-branch global phase is unobservable. This makes the phased equivalence
reduce exactly to the phaseless `CircuitAction` equivalence when no angles are
present, and lets measurement-based "ejection" gadgets compare equal to the
operation they implement directly.

Provenance is plumbed through the `Simulation` trait (default defers to
`allocate_random_bit`; `PhasedOutcomeCompleteSimulation` overrides to tag the
bit), the `Circuit`/`CircuitBuilder` replay (`Instruction::AllocateRandomBit`
gains a `symbolic_angle` flag), and the Python bindings (+ `.pyi`).

Tests: Z-basis ejection of symbolic Z-rotations vs the direct rotation (Rust +
Python), a miscorrected-ejection detection test, and an angle-free Z-diagonal
Clifford ejection proving phased == phaseless without symbolic angles. The
`verifying-symbolic-rotations.ipynb` notebook gains an ejection section and is
migrated to `allocate_symbolic_angle`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Add the X-basis dual of the measurement-based ejection gadget: ancillas in
|+>, CNOTs reversed (control = ancilla, target = system), an X-diagonal
operation on the ancillas, destructive Z-basis ancilla measurement, and a
conditional X correction per `1` outcome. This whole gadget is the conjugation
of the (already verified) Z-basis gadget by a transversal Hadamard, so it must
equal applying the same X-diagonal operation directly to the system qubits.

- phased_action_test.rs: symbolic X-rotation ejection (`x_ejection_channel`
  etc.) with single/two/three-qubit and repeated-angle cases, mirroring the
  Z-basis helpers and asserting symmetric phase-aware equivalence.
- action_test.rs: the angle-free `OutcomeCompleteSimulation` case as a proptest
  ejecting a random X-diagonal Clifford, obtained by Hadamard-conjugating the
  existing `arbitrary_diagonal_clifford` generator, and compared to the direct
  unitary action exactly like the Z-basis `diagonal_unitary_ejection_proptest`.

Tests only; no library changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Add ejection tests for diagonal channels that mix symbolic rotations
(virtual bits) with non-destructive stabilizer measurements (true
observed bits), exercising all three provenance classes at once
(virtual angles, observed measurements, marginalized readouts).

- phased_action_test.rs: Z- and X-basis channel ejection with
  non-destructive measurements, compared via the default `is_equivalent`
  (angle bits 1:1, measurement bits identity-by-order, readout bits
  projected).
- action_test.rs: `diagonal_measure_x_ejection_proptest`, the X-basis
  dual of the existing Z-basis measurement-ejection proptest, via
  Hadamard duality (`x_paulis_from_z_paulis`).

Tests only; no library behaviour changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…ation

Section 4.1 of arXiv:2603.24717 reduces verifying
C1 exp(iα Z) C2|0> == D1 exp(iα Z) D2|0> (for all α) to a single exact
stabilizer-state equality C1 Z^a C2|0> == D1 Z^a D2|0> with a symbolic
exponent. This needs no dedicated API: the check is `phased_action_of` +
`PhasedCircuitAction::is_equivalent`, the phased analog of how
OutcomeCompleteSimulation does phaseless equality checking.

- phased_action_test.rs: state-preparation (inputs = []) verification
  tests for the C1 Z^a C2|0> construction -- equal factorizations
  (CNOT-conjugated ZZ rotation), a phase-only difference detected as
  exactly one RelativePhase, and the multi-angle generalization.
- examples/verifying-circuit-equivalence.ipynb: a focused notebook
  illustrating the Python verification workflow (allocate_symbolic_angle
  -> conditional Z -> phased_action -> is_equivalent), float-free.

Tests + notebook only; no library or binding changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Introduce `Simulation::symbolic_pauli_exp` (Rust) and `apply_symbolic_pauli_exp`
(Python) so users express `exp(iα P)` directly instead of conditioning a Pauli on
an allocated angle. The name mirrors the existing fixed-angle `pauli_exp` /
`apply_pauli_exp`. The new method is a thin default over `conditional_pauli`, so no
core simulator behaviour changes.

User-facing docs no longer mention the virtual-bit / conditional-Pauli plumbing:
`allocate_symbolic_angle` is documented purely as "allocate a rotation angle" with
the cross-circuit one-to-one allocation-order correspondence that makes equivalence
checks meaningful.

Notebooks:
- verifying-symbolic-rotations.ipynb: use the high-level `apply_symbolic_pauli_exp`
  throughout (terminology is "Pauli exponent", not "rotation"); use the explicit
  `prepare_bell_pairs` Choi convention (matching zz-measurement-verification.ipynb)
  instead of a custom `choi_action` wrapper; drop all "virtual/true bit" framing; and
  finish with a richer ejection example -- a three-qubit Z-diagonal channel (three
  overlapping Z-Pauli exponents plus a non-destructive three-qubit parity
  measurement) ejected through ancillas.
- verifying-circuit-equivalence.ipynb: remove stray implementation-detail wording.

Tests: migrate genuine rotation call sites in phased_action_test.rs to
`symbolic_pauli_exp`; measurement corrections stay as `conditional_pauli`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Previously `allocate_symbolic_angle` (Python) returned a raw `int` outcome id, and
two circuits' angles were said to correspond "in allocation order". That coupling was
implicit and brittle, and the integer leaked an internal representation (it is a
random-bit index, not the angle's logical subscript).

Expose symbolic angles in Python as an opaque `SymbolicAngle` handle instead. Its only
observable feature is `index` -- the subscript k in alpha_k, fixed by allocation order
-- which is exactly what the phased equivalence check pairs between two circuits. New
ergonomics:

- `allocate_symbolic_angle() -> SymbolicAngle`
- `allocate_symbolic_angles(count) -> list[SymbolicAngle]` to allocate a circuit's
  angles up front
- `symbolic_angles` property to retrieve all allocated angles, so `angles[k]` is alpha_k
- `apply_symbolic_pauli_exp(observable, angle: SymbolicAngle)`

Because the handle is opaque it can only be consumed by `apply_symbolic_pauli_exp`, not
fed back into `apply_conditional_pauli`, which keeps symbolic-angle provenance flowing
through the symbolic API. The Rust core is unchanged: it keeps the uniform
`OutcomeId = usize` model (shared by measurements, random bits and angles, and used by
the `Circuit`/`Instruction` replay machinery); the opaque handle is a Python-binding
concern, consistent with the repo's "Pythonic, not 1:1" binding guidance.

- simulation.rs: add `SymbolicAngle` pyclass (frozen, with `index`/`__eq__`/`__hash__`/
  `__repr__`) and the allocation/accessor/apply methods above.
- paulimer.pyi: stub `SymbolicAngle` and the new signatures; add to `__all__`.
- verifying-symbolic-rotations.ipynb: the ejection example now allocates its angles with
  `allocate_symbolic_angles(3)` and refers to them by index, making the cross-circuit
  correspondence explicit; prose describes angles as opaque, index-identified handles.
- simulation_test.py: pass symbolic angles through `apply_symbolic_pauli_exp` (measurement
  corrections keep `apply_conditional_pauli`).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…logy)

M1: Correct the user-facing docstrings for phased_action / PhasedCircuitAction /
is_equivalent in paulimer.pyi to state that only symbolic-angle bits are matched
one-to-one by index, while genuine measurement (true) random bits are marginalized
(not "every random bit mapped one-to-one"). Reword a stale "rotations" mention.

M2: apply_clifford on PhasedOutcomeCompleteSimulation previously panicked across the
FFI boundary (the phased simulator's Rust clifford is unimplemented! because a
phaseless CliffordUnitary does not determine the exact global phase it tracks). Thread
a clifford_supported flag through the impl_simulation! macro so the phased binding
raises a clean NotImplementedError instead, directing users to apply_unitary /
apply_pauli / apply_pauli_exp. Document the behavior in the .pyi stub.

L1: Scrub residual "rotation" / "true bit" terminology from the example notebooks in
favor of "Pauli exponent" / "measurement outcome"; re-execute both notebooks.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Add sign-flip and angle-permutation negative tests plus proptest/hypothesis
randomization for PhasedCircuitAction equivalence. Flipping any subset of
symbolic Pauli-exponent signs leaves the phaseless action unchanged but must
yield exactly RelativePhase; permuting the symbolic-angle allocation order over
distinct Paulis must be detected as inequivalent (identity permutation stays
equivalent). Mirrored in Python via hypothesis.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Make the repository's user-facing docs aware of the phased outcome-complete
simulator and its symbolic-angle circuit-verification workflow:

- Top-level README: note exact global-phase tracking in the pauliverse bullet
  and add a "Stabilizer Simulation (pauliverse)" Rust quick-start showing
  PhasedOutcomeCompleteSimulation with a higher-weight symbolic exponent
  e^{i alpha Z0 Z1}.
- Python bindings README: add a "Verifying parameterised circuits with symbolic
  angles" quick-start, a PhasedOutcomeCompleteSimulation feature bullet, and a
  use-case sentence.
- verifying-symbolic-rotations.ipynb: add a mixed-basis (non-Z), higher-weight
  Pauli-exponent example (e^{i alpha X0 Z1} == H0 e^{i alpha Z0 Z1} H0) to make
  the "arbitrary Pauli of any weight" capability unambiguous.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Rename terse/single-letter variables and parameters (n, q, c, t, a, b,
m, x, z, ab, bb, cb, tb, p, p1, p2, sp1, sp2, u, o, ...) to descriptive
names (qubit_count, qubit, control, target, first_qubit, second_qubit,
matrix, x_bits, z_bits, pauli, first_pauli, second_pauli, ...) in the
dense-statevector oracle tests for PhasedCliffordUnitary and
PhasedOutcomeCompleteSimulation, matching the naming conventions used
elsewhere in the test suite (e.g. pauliverse/tests/action_test.rs).

No behavioral changes; cargo test confirms all 12 affected tests still
pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…ation tests

Add PhasedOutcomeCompleteSimulation to SIMULATION_CLASSES so it gets the
same generic parametrized coverage as the other three simulator classes
(apply_permutation, is_stabilizer, measure with hint, allocate_random_bit,
reserve_qubits, reserve_outcomes, etc.), which it was previously missing
entirely.

apply_clifford genuinely cannot work on this class: CliffordUnitary only
encodes how a unitary conjugates the Pauli group, discarding the absolute
global phase information PhasedOutcomeCompleteSimulation must track, so
the binding raises NotImplementedError for it (simulation.rs). Introduce
CLIFFORD_CAPABLE_SIMULATION_CLASSES, scoped to the three classes that do
support apply_clifford, and use it only for the two apply_clifford tests.

Verified with maturin develop --release + pytest: 329 passed (up from
146 in simulation_test.py alone, now including 30 new phased-class cases).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Introduce `clifford_to_pauli_exponents` in `paulimer::clifford`: an exact
decomposition of a `CliffordUnitary` into an ordered product of pi/4 Pauli
exponents `exp(i pi/4 P)`. The reconstruction reproduces the full tableau,
including Pauli-image signs, so replaying the factors on a phased operator
(`PhasedCliffordUnitary::left_mul_pauli_exp`) yields a well-defined global
phase. This is the primitive needed to recover the absolute global phase in
the auxiliary-qubit separation of arXiv:2603.24717 (Sec 4.5).

The algorithm reduces a working copy of the Clifford to the identity by
left-multiplying pi/4 exponents (per-qubit column reduction of the X and Z
images), then returns the inverse exponents in reverse order.

- New module `paulimer/src/clifford/decomposition.rs`, re-exported from
  `clifford.rs`.
- Rust tests in `clifford_test.rs`: identity-is-empty, fixed examples, and a
  proptest roundtrip over random Cliffords (n in 0..6).
- Python binding `CliffordUnitary.to_pauli_exponents()` with `.pyi` stub and
  tests; stubtest clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Surface clifford_to_pauli_exponents / CliffordUnitary.to_pauli_exponents in the
user-facing docs:

- paulimer/README.md: add a Clifford feature bullet, a Quick-Start snippet that
  decomposes a Clifford and rebuilds it via left_mul_pauli_exp, and a
  documentation entry pointing at src/clifford/decomposition.rs.
- Python bindings README: add a "Decomposing a Clifford into pi/4 Pauli
  exponents" quick-start and mention to_pauli_exponents in the CliffordUnitary
  feature bullet.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Restore the standalone dense-Pauli controlled-operation test header so pytest collects it independently from the Pauli-exponent round-trip test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Co-authored-by: GPT-5.6 Sol <noreply@openai.com>
Cite section 4.3, where auxiliary-qubit separation is defined, rather than section 4.5.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Co-authored-by: GPT-5.6 Sol <noreply@openai.com>
Marcus P S (marcusps) and others added 2 commits July 18, 2026 11:35
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…d Clifford

Add trailing semicolons in the left_mul_x/y/z closures to match the
sibling gate methods and unblock the -D clippy::pedantic CI step.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Marcus P S (marcusps) and others added 27 commits July 18, 2026 13:45
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…jection test

Add the two symbolic-rotation notebook scenarios that lacked a Rust test:
HZH = X-exp, and mixed-basis X0Z1 = H0.ZZ.H0 (distinct from bare ZZ).

Refactor the core Z-ejection helpers in place for readability: document the
three ejection phases (entangle, rotate remotely, measure-and-correct), state
the ejection invariant on check_z_ejection, and clarify the local-vs-support
indexing of the shared helpers. No test coverage removed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address review feedback that the phased-outcome-simulation tests and the
pre-existing phased-Clifford tests each carried a near-identical hand-rolled
full state vector simulator. Extract the shared oracle (C, zeta8, Dense,
gate_matrix, statevector, pauli_arrays, close) into a new private,
unpublished `dense-oracle` crate and have both test suites reuse it.

The change is additive to non-test code: no crate's src/ is touched, only
the two test files, their dev-dependencies, and the workspace member list.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
…hints

A review pointed out that `PhasedOutcomeCompleteSimulation::measure_with_hint`
produced the wrong post-measurement state and outcome sign whenever the
anti-commuting hint carried a negative sign (the `(-1)^alpha` branch of case 5
of Algorithm 4.2).

Generalize the reviewer's reproduction into a property-based (proptest) test
and add it to the suite: over random Clifford states it measures the
destabilizer `image_x(q)` while hinting with the (optionally negated)
stabilizer `image_z(q)`, and asserts the measured observable stays a stabilizer
whose conditional sign matches the reported outcome. This test fails on the
old code (shrinking to measuring X on |0> with hint -Z) and its minimal
counterexample is pinned via the checked-in .proptest-regressions file.

Adopt the reviewer's proposed fix: instead of applying a global `(-1)^alpha`
phase, relabel the reported outcome (`m = r XOR alpha`) via `outcome_shift`,
which makes the tracked stabilizer sign and the reported outcome agree.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
…outcome-complete-sim

# Conflicts:
#	pauliverse/Cargo.toml
…plete-sim' into masilv/phased-outcome-complete-sim

# Conflicts:
#	pauliverse/Cargo.toml
Co-authored-by: Juan M. Bello-Rivas <jmbr@superadditive.com>
Co-authored-by: Juan M. Bello-Rivas <jmbr@superadditive.com>
Addresses jmbr's review: move the shared statevector oracle under test-utils/,
set version 0.0.0, and use num-complex instead of a bespoke complex type.

microsoft#115 (comment)
microsoft#115 (comment)
microsoft#115 (comment)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
Addresses jmbr's review: build `difference` via map/collect and iterate the
Pauli's x/z bit supports directly instead of materializing helper vectors.

microsoft#115 (comment)
microsoft#115 (comment)
microsoft#115 (comment)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
Addresses jmbr's review: replace the hand-rolled RNG loop with a proptest Gate
strategy tracking the dense statevector.

microsoft#115 (comment)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
Addresses jmbr's review: share a phased_action helper, collect symbolic angles
inline, and drop the now-unused indicator_to_bitvec.

microsoft#115 (comment)
microsoft#115 (comment)
microsoft#115 (comment)
microsoft#115 (comment)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
Addresses jmbr's review: delegate the branch-phase computation to the identical
PhaseData routine in action.rs rather than duplicating it.

microsoft#115 (comment)
microsoft#115 (comment)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
Addresses jmbr's review: use enumerate().take() with the bound bit so the
clippy-suggested pattern stays warning-clean.

microsoft#115 (comment)
microsoft#115 (comment)
microsoft#115 (comment)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
Addresses jmbr's review: generate the preparation circuit with a proptest Gate
strategy mirroring phased_clifford_dense.

microsoft#115 (comment)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
Addresses jmbr's review: remove the phased_action and measure_with_hint
proptest-regressions files.

microsoft#115 (comment)
microsoft#115 (comment)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
Addresses jmbr's review: revert the references/ addition.

microsoft#115 (comment)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
Pass Complex::norm_sqr directly instead of wrapping it in a closure, fixing a
clippy::pedantic error surfaced by CI's newer toolchain.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
Addresses jmbr: replace the allocating PhaseData round-trip in
output_phase_exponent with a closure-based phase_form_exponent shared by the
simulator and PhaseData, evaluating the phase form directly over self.

microsoft#115 (comment)
microsoft#115 (comment)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
…uli-exp-decomp

Bring the fully-reviewed phased outcome-complete simulation branch up the stack.
This carries all of jmbr's PR microsoft#115 review fixes: dense-oracle relocated under
test-utils/ with num-complex, deduplicated phased action + shared
phase_form_exponent helper, idiomatic bit iteration in phased_clifford, proptest
Gate-strategy tests, and dropped proptest-regressions seeds.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
Preempts jmbr-style review notes on the Clifford->pi/4 decomposition:
- drop the redundant `Reduction.qubit_count` field and derive it from
  `working.num_qubits()` at each use, removing duplicated state;
- fold the reduction-math explanation from an inline comment into the
  `clifford_to_pauli_exponents` doc comment under a `# Algorithm` heading.

Behavior-preserving; roundtrip proptest and examples still pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
Marcus P S (marcusps) pushed a commit to marcusps/qdk-ec that referenced this pull request Jul 24, 2026
Apply the conventions established while addressing @jmbr's review on the
phased-outcome / decomposition stack (PRs microsoft#115/microsoft#116) to the transvection
decomposition, anticipating the same feedback here:

- Replace the seed + internal-RNG proptests (`seed in any::<u64>()` feeding
  `CliffordUnitary::random`) with a `Gate`-sequence `Strategy`, mirroring
  phased_clifford_dense.rs and measure_with_hint_sign_test.rs, so a failing
  input shrinks to a minimal gate sequence instead of an opaque seed. The
  deterministic sweep (which needs no shrinking) keeps using a seeded RNG.
- Derive `qubit_count` inside `next_transvection` from `working.num_qubits()`
  instead of threading it as a parameter, matching the earlier "derive qubit
  count" tidy on the Gaussian-elimination decomposition.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
Marcus P S (marcusps) pushed a commit to marcusps/qdk-ec that referenced this pull request Jul 25, 2026
…inimal

Update the minimal-decomposition rung with the latest from the lower rung
clifford-to-pauli-exp-unphased (79c66e3): the Gate-strategy proptests and the
param-less next_transvection tidy, applying the @jmbr review conventions from
PRs microsoft#115/microsoft#116/microsoft#117 to this branch too.

Also align the branch's own minimal-decomposition tests with those conventions:
convert the remaining seed + internal-RNG proptests (minimal_reproduces_symplectic_action,
minimal_is_r_or_r_plus_one_and_at_most_greedy) to the shared Gate strategy so they
shrink to a minimal gate sequence, and drop the committed
transvection_test.proptest-regressions seed file. The deterministic seeded sweeps
(which need no shrinking) keep using random_clifford.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 16f923fe-a72a-4430-97b0-b7677f48dfb7
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.

1 participant