Source code for qarp.cutting._decompositions

"""QPD gate decompositions.

Each function takes a prefix command list and returns 6 experiment command
lists plus a coefficient array.  Gate angles are in radians (qarpx convention).

Mid-circuit measurements use _measure_cmd(), which creates a properly formed
qx.Command with cbits set — routing through the qarpx trajectory simulation
path (the same infrastructure used by ConditionalBlock).
"""

import numpy as np
import sympy

import qarpx as qx

from ._internals import _cmd, _measure_cmd


[docs] def decompose_cx( prefix: list, n_qubits: int, idx: list, idx_to_be_used_bit: np.ndarray, ) -> tuple[list, np.ndarray]: """QPD decomposition of a CX gate into 6 single-qubit experiments. Args: prefix: Command list accumulated before this cut. n_qubits: Qubit count of the circuit. idx: [ctrl_qubit, tgt_qubit]. idx_to_be_used_bit: Array of 6 ints; idx_to_be_used_bit[i] is the next available QPD cbit index for experiment i. Returns: (experiments, coefficients) where experiments is a list of 6 command lists. """ cbit = int(idx_to_be_used_bit[0]) # all 6 start at the same cbit cmds_1 = list(prefix) + [ _cmd(qx.GateType.Sdg, idx[0]), _cmd(qx.GateType.H, idx[1]), _cmd(qx.GateType.Sdg, idx[1]), _cmd(qx.GateType.H, idx[1]), ] cmds_2 = list(prefix) + [ _cmd(qx.GateType.S, idx[0]), _cmd(qx.GateType.H, idx[1]), _cmd(qx.GateType.S, idx[1]), _cmd(qx.GateType.H, idx[1]), ] cmds_3 = list(prefix) + [ _cmd(qx.GateType.Sdg, idx[0]), _measure_cmd(idx[0], cbit), ] cmds_4 = list(prefix) + [ _cmd(qx.GateType.Sdg, idx[0]), _measure_cmd(idx[0], cbit), _cmd(qx.GateType.H, idx[1]), _cmd(qx.GateType.Z, idx[1]), _cmd(qx.GateType.H, idx[1]), ] cmds_5 = list(prefix) + [ _cmd(qx.GateType.H, idx[1]), _cmd(qx.GateType.Sdg, idx[1]), _measure_cmd(idx[1], cbit), _cmd(qx.GateType.H, idx[1]), ] cmds_6 = list(prefix) + [ _cmd(qx.GateType.Z, idx[0]), _cmd(qx.GateType.H, idx[1]), _cmd(qx.GateType.Sdg, idx[1]), _measure_cmd(idx[1], cbit), _cmd(qx.GateType.H, idx[1]), ] subexperiments = [cmds_1, cmds_2, cmds_3, cmds_4, cmds_5, cmds_6] coefficients = np.array([0.5, 0.5, 0.5, -0.5, 0.5, -0.5]) return subexperiments, coefficients
[docs] def decompose_rzz( prefix: list, n_qubits: int, idx: list, idx_to_be_used_bit: np.ndarray, parameter, ) -> tuple[list, np.ndarray]: """QPD decomposition of an RZZ gate. Args: prefix: Command list accumulated before this cut. n_qubits: Qubit count. idx: [q0, q1]. idx_to_be_used_bit: Next available QPD cbit per experiment. parameter: RZZ rotation angle in radians (qarpx convention). May be a float or sympy.Symbol for parametric circuits. Returns: (experiments, coefficients) """ # Sign convention: qarpx RZZ(θ) = exp(-i θ/2 Z⊗Z). # The QPD formula uses the negated angle; coefficients are # cos²(θ/2), sin²(θ/2), ±sin(θ)/2 where θ = |parameter|. parameter_rad = -parameter cbit = int(idx_to_be_used_bit[0]) a_1 = sympy.cos(parameter_rad / 2.0) ** 2 a_2 = sympy.sin(parameter_rad / 2.0) ** 2 a_3 = (-1) * sympy.sin(parameter_rad) / 2.0 a_4 = sympy.sin(parameter_rad) / 2.0 a_5 = a_3 a_6 = a_4 cmds_1 = list(prefix) cmds_2 = list(prefix) + [ _cmd(qx.GateType.Z, idx[0]), _cmd(qx.GateType.Z, idx[1]), ] cmds_3 = list(prefix) + [ _measure_cmd(idx[0], cbit), _cmd(qx.GateType.S, idx[1]), ] cmds_4 = list(prefix) + [ _measure_cmd(idx[0], cbit), _cmd(qx.GateType.Sdg, idx[1]), ] cmds_5 = list(prefix) + [ _cmd(qx.GateType.S, idx[0]), _measure_cmd(idx[1], cbit), ] cmds_6 = list(prefix) + [ _cmd(qx.GateType.Sdg, idx[0]), _measure_cmd(idx[1], cbit), ] subexperiments = [cmds_1, cmds_2, cmds_3, cmds_4, cmds_5, cmds_6] coefficients = np.array([a_1, a_2, a_3, a_4, a_5, a_6]) return subexperiments, coefficients
[docs] def decompose_cy(prefix, n_qubits, idx, idx_to_be_used_bit) -> tuple[list, np.ndarray]: raise NotImplementedError("CY gates are not yet supported with circuit cutting.")
[docs] def decompose_cz(prefix, n_qubits, idx, idx_to_be_used_bit) -> tuple[list, np.ndarray]: raise NotImplementedError("CZ gates are not yet supported with circuit cutting.")
[docs] def decompose_crx(prefix, n_qubits, idx, idx_to_be_used_bit) -> tuple[list, np.ndarray]: raise NotImplementedError("CRX gates are not yet supported with circuit cutting.")
[docs] def decompose_cry(prefix, n_qubits, idx, idx_to_be_used_bit) -> tuple[list, np.ndarray]: raise NotImplementedError("CRY gates are not yet supported with circuit cutting.")
[docs] def decompose_crz(prefix, n_qubits, idx, idx_to_be_used_bit) -> tuple[list, np.ndarray]: raise NotImplementedError("CRZ gates are not yet supported with circuit cutting.")