Skip to content

Add the Phase(gamma) unitary with exact naming, structural control, and hardware lowering - #672

Open
ciaranra wants to merge 9 commits into
devfrom
phase-gate
Open

Add the Phase(gamma) unitary with exact naming, structural control, and hardware lowering#672
ciaranra wants to merge 9 commits into
devfrom
phase-gate

Conversation

@ciaranra

@ciaranra ciaranra commented Sep 2, 2026

Copy link
Copy Markdown
Member

Stacked on #668 (the branch includes its commits; merge #668 first).

What

One new unitary, Phase(gamma), with one rule: on an operand set S of zero, one, or two qubits it multiplies the amplitude by exp(i gamma) on the subspace where every qubit in S is |1> and leaves everything else alone.

  • S = {} is a global phase (the scalar exp(i gamma)).
  • S = {q} is diag(1, exp(i gamma)), exactly U(0, 0, gamma).
  • S = {c, t} is diag(1, 1, 1, exp(i gamma)).
  • |S| > 2 is refused at construction.
  • Controlling a Phase on S by a qubit c is structurally Phase on S + {c}.

This is layers 1 and 2 of the Phase(gamma) design (representation and hardware lowering). No GateType, byte-level command, simulator fast path, or ingress rewiring yet; those follow once the benchmark decides the command shape.

API (pecos-core)

  • Unitary::Phase { gamma: Angle64, num_qubits: u8 } and UnitaryRep::phase_gate(gamma, qubits).
  • UnitaryRep::control(self, c) -> Result<UnitaryRep, ControlError>: structural for Phase; refuses a control already in S, a third operand, a non-Phase rep, and a descriptor whose operand count disagrees with its qubit list.
  • controlled_rotations::lower_phase(gamma_radians, &[QubitId]) -> Vec<Gate>: {} lowers to no gates (hardware cannot see a scalar; the caller keeps it), {q} to U(0, 0, gamma), {c, t} through lower_cphase.
  • Dense conversion builds the diagonal from the rule directly (no half-angle, so negative angles need no representative choice).
  • is_clifford reads the shared exact Clifford-angle table (try_simplify_rotation): one qubit at multiples of pi/2, two qubits at 0 and pi. to_named_gate returns a name only when the matrices are exactly equal: I, SZ, Z, SZdg, T, Tdg on one qubit, CZ on two. Adjoint, is_hermitian, to_pauli_string, is_pauli_equivalent/try_to_pauli, Unitary::is_pauli/try_to_pauli, to_clifford_rep, the hardware decomposition, the phase() accessor (a zero-operand Phase is the scalar itself), and circuit-diagram rendering handle Phase.

Fix found on the way

lower_cphase halved the source f64 before Angle64 reduction, so at lambda = 2pi (mod 4pi) the RZZ(-pi) and RZ(+pi) legs both stored HALF_TURN and the lowering executed as -I instead of I (QASM/PHIR cp(2pi) on dev). CPhase is 2π-periodic, so the angle is now reduced to (-pi, pi] first; every halved angle then lies in (-pi/2, pi/2] and the lowering is exact for every input. CRZ/CRX/CRY are 4π-periodic and cannot use that reduction; their documented ±1 at theta = 2pi (mod 4pi) is intrinsic to the two-gate form and is filed as #670 (the exact fix is a zero-operand Phase from the ingress, which this PR makes possible).

Tests

crates/pecos-simulators/tests/phase_gate_contract.rs is the specification: the matrix follows the rule at nine angles including ±2pi, pi, 3pi/2, for S = {}, {0}, {1}, {0,1}, {1,0}; single-qubit Phase equals U(0,0,gamma) entrywise; the lowering composed in the dense path and executed on StateVecSoA equals the rule entrywise (1e-12); control() composes and refuses as specified; Clifford membership and exact naming follow the angle table. Unit tests cover the control() error variants, lower_phase on {}, the T/Tdg names, the Pauli views, and the zero-operand phase().

Follow-ups filed

Verification

cargo fmt --all -- --check; cargo clippy --workspace --all-targets -- -D warnings (default and --all-features lanes); pecos rust test --profile debug (full recipe); just lint check. Mutation: removing the lower_cphase reduction fails both lowering tests in the contract. Two independent reviews (fresh-context and cross-model) ran on the diff; every finding is fixed or refuted in this description.

Base automatically changed from dense-rotation-signed-halving to dev September 4, 2026 13:11
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