qml.transforms.rz_phase_gradient

rz_phase_gradient(tape, angle_wires, phase_grad_wires, work_wires)[source]

Quantum function transform to decompose all instances of RZ gates into additions using a phase gradient resource state.

For example, an RZ gate with angle \(\phi = (0 \cdot 2^{-1} + 1 \cdot 2^{-2} + 0 \cdot 2^{-3}) 2\pi\) is translated into the following routine, where the angle is conditionally prepared on the angle_wires in binary and added to a phase_grad_wires register semi-inplace via SemiAdder.

target: ─RZ(ϕ)─ = ────╭●──────────────╭●────exp(iϕ/2)─┤
 ang_0:           ────├|0⟩─╭SemiAdder─├|0⟩────────────┤
 ang_1:           ────├|1⟩─├SemiAdder─├|1⟩────────────┤
 ang_2:           ────╰|0⟩─├SemiAdder─╰|0⟩────────────┤
 phg_0:           ─────────├SemiAdder─────────────────┤
 phg_1:           ─────────├SemiAdder─────────────────┤
 phg_2:           ─────────╰SemiAdder─────────────────┤

For this routine to work, the provided phase_grad_wires need to hold a phase gradient state \(|\nabla Z\rangle = \frac{1}{\sqrt{2^n}} \sum_{m=0}^{2^n-1} e^{2 \pi i \frac{m}{2^n}} |m\rangle\). Because this state is not modified and can be re-used at a later stage, the transform does not prepare it but rather assumes it has been prepared on those wires at an earlier stage.

Note that SemiAdder requires additional work_wires (not shown in the diagram) for the semi-in-place addition \(\text{SemiAdder}|x\rangle_\text{ang} |y\rangle_\text{phg} = |x\rangle_\text{ang} |x + y\rangle_\text{phg}\).

More details can be found on page 4 in arXiv:1709.06648 and Figure 17a in arXiv:2211.15465 (a generalization to multiplexed RZ rotations is provided in Figure 4 in arXiv:2409.07332).

Note that technically, this circuit realizes PhaseShift, i.e. \(R_\phi(\phi) = R_Z(\phi) e^{i\phi/2}\). The additional global phase is taken into account in the decomposition.

Parameters:
  • tape (QNode or QuantumTape or Callable) – A quantum circuit containing RZ gates.

  • angle_wires (Wires) – The qubits that conditionally load the angle \(\phi\) of the RZ gate in binary as a multiple of \(2\pi\). The length of the angle_wires implicitly determines the precision with which the angle is represented. E.g., \((2^{-1} + 2^{-2} + 2^{-3}) 2\pi\) is exactly represented by three bits as 111.

  • phase_grad_wires (Wires) – The catalyst qubits with a phase gradient state prepared on them. Needs to be at least the length of angle_wires and will only use the first len(angle_wires).

  • work_wires (Wires) – Additional work wires to realize the SemiAdder between the angle_wires and phase_grad_wires. Needs to be at least b-1 wires, where b=len(phase_grad_wires) is the precision of the angle \(\phi\).

Returns:

The transformed circuit as described in qml.transform.

Return type:

qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function]

Example

from functools import partial

import numpy as np

import pennylane as qml
from pennylane.transforms.rz_phase_gradient import rz_phase_gradient

precision = 3
phi = (1 / 2 + 1 / 4 + 1 / 8) * 2 * np.pi
wire = "targ"
angle_wires = [f"ang_{i}" for i in range(precision)]
phase_grad_wires = [f"phg_{i}" for i in range(precision)]
work_wires = [f"work_{i}" for i in range(precision - 1)]
wire_order = [wire] + angle_wires + phase_grad_wires + work_wires


def phase_gradient(wires):
    # prepare phase gradient state
    qml.X(wires[-1])
    qml.QFT(wires)


@partial(
    rz_phase_gradient,
    angle_wires=angle_wires,
    phase_grad_wires=phase_grad_wires,
    work_wires=work_wires,
)
@qml.qnode(qml.device("default.qubit"))
def rz_circ(phi, wire):
    phase_gradient(phase_grad_wires)  # prepare phase gradient state

    qml.Hadamard(wire)  # transform rotation
    qml.RZ(phi, wire)
    qml.Hadamard(wire)  # transform rotation

    return qml.probs(wire)

In this example we perform the rotation of an angle of \(\phi = (0.111)_2 2\pi\). Because phase shifts are trivial on computational basis states, we transform the \(R_Z\) rotation to \(R_X = H R_Z H\) via two Hadamard gates.

Note that for the transform to work, we need to also prepare a phase gradient state on the phase_grad_wires.

Overall, the full circuit looks like the following:

>>> print(qml.draw(rz_circ, wire_order=wire_order)(phi, wire))
  targ: ──H──────╭(|Ψ⟩)@SemiAdder@(|Ψ⟩)──H─╭GlobalPhase(2.75)─┤  Probs
 ang_0: ─────────├(|Ψ⟩)@SemiAdder@(|Ψ⟩)────├GlobalPhase(2.75)─┤
 ang_1: ─────────├(|Ψ⟩)@SemiAdder@(|Ψ⟩)────├GlobalPhase(2.75)─┤
 ang_2: ─────────├(|Ψ⟩)@SemiAdder@(|Ψ⟩)────├GlobalPhase(2.75)─┤
 phg_0: ────╭QFT─├(|Ψ⟩)@SemiAdder@(|Ψ⟩)────├GlobalPhase(2.75)─┤
 phg_1: ────├QFT─├(|Ψ⟩)@SemiAdder@(|Ψ⟩)────├GlobalPhase(2.75)─┤
 phg_2: ──X─╰QFT─├(|Ψ⟩)@SemiAdder@(|Ψ⟩)────├GlobalPhase(2.75)─┤
work_0: ─────────├(|Ψ⟩)@SemiAdder@(|Ψ⟩)────├GlobalPhase(2.75)─┤
work_1: ─────────╰(|Ψ⟩)@SemiAdder@(|Ψ⟩)────╰GlobalPhase(2.75)─┤

The additional work wires are required by the SemiAdder. Executing the circuit, we get the expected result:

>>> rz_circ(phi, wire)
array([0.85355339, 0.14644661])