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
RZgates into additions using a phase gradient resource state.For example, an
RZgate 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 theangle_wiresin binary and added to aphase_grad_wiresregister semi-inplace viaSemiAdder.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_wiresneed to hold a phase gradient state \(|\nabla n\rangle = \frac{1}{\sqrt{N}} \sum_{m=0}^{N-1} e^{-2 \pi i \frac{m}{N}} |m\rangle\), where \(n\) is the number of qubits and \(N=2^n\). 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
SemiAdderrequires additionalwork_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
RZrotations 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
RZgates.angle_wires (Wires) – The qubits that conditionally load the angle \(\phi\) of the
RZgate in binary as a multiple of \(2\pi\). The length of theangle_wiresimplicitly 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 as111.phase_grad_wires (Wires) – The catalyst qubits with a phase gradient state prepared on them. Needs to be at least the length of
angle_wiresand will only use the firstlen(angle_wires).work_wires (Wires) – Additional work wires to realize the
SemiAdderbetween theangle_wiresandphase_grad_wires. Needs to be at leastb-1wires, whereb=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 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): for i, w in enumerate(wires): qml.H(w) qml.PhaseShift(-np.pi/2**i, w) @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
Hadamardgates.Note that for the transform to work, we needed to also prepare a phase gradient state on the
phase_grad_wiresviaphase_gradient.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: ──H──Rϕ(-3.14)─├(|Ψ⟩)@SemiAdder@(|Ψ⟩)────├GlobalPhase(2.75)─┤ phg_1: ──H──Rϕ(-1.57)─├(|Ψ⟩)@SemiAdder@(|Ψ⟩)────├GlobalPhase(2.75)─┤ phg_2: ──H──Rϕ(-0.79)─├(|Ψ⟩)@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 following result:>>> rz_circ(phi, wire) array([0.853..., 0.146...])
This matches the expected result of just applying a simple
RXgate:>>> np.abs(qml.RX(phi, 0).matrix()[:, 0]) ** 2 array([0.853..., 0.146...])