Source code for qarp.blocks._primitives.givens_block
from typing import Optional, Union
from sympy import Symbol
from .._block import SimpleBlock, as_param
_to_param = as_param # the single §13 coercion (multi-symbol / non-linear → ValueError)
[docs]
class GivensBlock(SimpleBlock):
def __init__(
self,
theta: Union[Symbol, float],
target_qubits: Optional[list[int]] = None,
name: str = "Givens",
):
"""Construct the Givens Rotation gate.
Follows Nam, npj Quantum Information (2020) 6:33 with the matrix:
::
[1 0 0 0]
[0 cos(theta / 2) -sin(theta / 2) 0]
[0 sin(theta / 2) cos(theta / 2) 0]
[0 0 0 1]
The parameter is in **radians**, matching qarpx's convention for
single-qubit rotations (``Rx/Ry/Rz``). ``theta`` may be float, sympy
Symbol, or a linear sympy expression in a single symbol.
Args:
theta: Rotation angle in radians.
target_qubits: The target qubits will act on when added to a Block object.
"""
self.theta = theta
super().__init__(
n_qubits=2,
target_qubits=target_qubits,
name=name,
)
[docs]
def build_vanilla(self) -> None:
# Decompose the Givens rotation via the Sdg / RXX / S sandwich
# (Nam et al.). ``self.theta`` is in radians; the inner RXX angle is
# ``theta/2``, implemented as ``CX(0,1) · Rx(-theta/2, q0) · CX(0,1)``
# (since ``RXX(α) = CX·Rx(-α, q0)·CX``).
alpha = self.theta / 2
self.sdg(0)
self.cx(0, 1)
self.rx(0, _to_param(-alpha))
self.cx(0, 1)
self.s(0)
self.sdg(1)
self.cx(0, 1)
self.rx(0, _to_param(alpha))
self.cx(0, 1)
self.s(1)