|
23 | 23 | from typing import Optional, Sequence, Tuple, TYPE_CHECKING
|
24 | 24 |
|
25 | 25 | import numpy as np
|
| 26 | +import sympy |
26 | 27 |
|
27 | 28 | from cirq import circuits, ops, linalg, protocols
|
28 | 29 | from cirq.transformers.analytical_decompositions import single_qubit_decompositions
|
|
32 | 33 | import cirq
|
33 | 34 |
|
34 | 35 |
|
| 36 | +def parameterized_2q_op_to_sqrt_iswap_operations( |
| 37 | + op: 'cirq.Operation', *, use_sqrt_iswap_inv: bool = False |
| 38 | +) -> protocols.decompose_protocol.DecomposeResult: |
| 39 | + """Tries to decompose a parameterized 2q operation into √iSWAP's + parameterized 1q rotations. |
| 40 | +
|
| 41 | + Currently only supports decomposing the following gates: |
| 42 | + a) `cirq.CZPowGate` |
| 43 | + b) `cirq.SwapPowGate` |
| 44 | + c) `cirq.ISwapPowGate` |
| 45 | + d) `cirq.FSimGate` |
| 46 | +
|
| 47 | + Args: |
| 48 | + op: Parameterized two qubit operation to be decomposed into sqrt-iswaps. |
| 49 | + use_sqrt_iswap_inv: If True, `cirq.SQRT_ISWAP_INV` is used as the target 2q gate, instead |
| 50 | + of `cirq.SQRT_ISWAP`. |
| 51 | +
|
| 52 | + Returns: |
| 53 | + A parameterized `cirq.OP_TREE` implementing `op` using only `cirq.SQRT_ISWAP` |
| 54 | + (or `cirq.SQRT_ISWAP_INV`) and parameterized single qubit rotations OR |
| 55 | + None or NotImplemented if decomposition of `op` is not known. |
| 56 | + """ |
| 57 | + gate = op.gate |
| 58 | + q0, q1 = op.qubits |
| 59 | + |
| 60 | + if isinstance(gate, ops.CZPowGate): |
| 61 | + return _cphase_symbols_to_sqrt_iswap(q0, q1, gate.exponent, use_sqrt_iswap_inv) |
| 62 | + if isinstance(gate, ops.SwapPowGate): |
| 63 | + return _swap_symbols_to_sqrt_iswap(q0, q1, gate.exponent, use_sqrt_iswap_inv) |
| 64 | + if isinstance(gate, ops.ISwapPowGate): |
| 65 | + return _iswap_symbols_to_sqrt_iswap(q0, q1, gate.exponent, use_sqrt_iswap_inv) |
| 66 | + if isinstance(gate, ops.FSimGate): |
| 67 | + return _fsim_symbols_to_sqrt_iswap(q0, q1, gate.theta, gate.phi, use_sqrt_iswap_inv) |
| 68 | + return NotImplemented |
| 69 | + |
| 70 | + |
| 71 | +def _sqrt_iswap_inv( |
| 72 | + a: 'cirq.Qid', b: 'cirq.Qid', use_sqrt_iswap_inv: bool = True |
| 73 | +) -> 'cirq.OP_TREE': |
| 74 | + """Optree implementing `cirq.SQRT_ISWAP_INV(a, b)` using √iSWAPs. |
| 75 | +
|
| 76 | + Args: |
| 77 | + a: The first qubit. |
| 78 | + b: The second qubit. |
| 79 | + use_sqrt_iswap_inv: If True, `cirq.SQRT_ISWAP_INV` is used instead of `cirq.SQRT_ISWAP`. |
| 80 | +
|
| 81 | + Returns: |
| 82 | + `cirq.SQRT_ISWAP_INV(a, b)` or equivalent unitary implemented using `cirq.SQRT_ISWAP`. |
| 83 | + """ |
| 84 | + return ( |
| 85 | + ops.SQRT_ISWAP_INV(a, b) |
| 86 | + if use_sqrt_iswap_inv |
| 87 | + else [ops.Z(a), ops.SQRT_ISWAP(a, b), ops.Z(a)] |
| 88 | + ) |
| 89 | + |
| 90 | + |
| 91 | +def _cphase_symbols_to_sqrt_iswap( |
| 92 | + a: 'cirq.Qid', b: 'cirq.Qid', turns: 'cirq.TParamVal', use_sqrt_iswap_inv: bool = True |
| 93 | +): |
| 94 | + """Implements `cirq.CZ(a, b) ** turns` using two √iSWAPs and single qubit rotations. |
| 95 | +
|
| 96 | + Output unitary: |
| 97 | + [[1, 0, 0, 0], |
| 98 | + [0, 1, 0, 0], |
| 99 | + [0, 0, 1, 0], |
| 100 | + [0, 0, 0, g]] |
| 101 | + where: |
| 102 | + g = exp(i·π·t). |
| 103 | +
|
| 104 | + Args: |
| 105 | + a: The first qubit. |
| 106 | + b: The second qubit. |
| 107 | + turns: The rotational angle (t) that specifies the gate, where |
| 108 | + g = exp(i·π·t/2). |
| 109 | + use_sqrt_iswap_inv: If True, `cirq.SQRT_ISWAP_INV` is used instead of `cirq.SQRT_ISWAP`. |
| 110 | +
|
| 111 | + Yields: |
| 112 | + A `cirq.OP_TREE` representing the decomposition. |
| 113 | + """ |
| 114 | + theta = sympy.Mod(turns, 2.0) * sympy.pi |
| 115 | + |
| 116 | + # -1 if theta > pi. Adds a hacky fudge factor so theta=pi is not 0 |
| 117 | + sign = sympy.sign(sympy.pi - theta + 1e-9) |
| 118 | + |
| 119 | + # For sign = 1: theta. For sign = -1, 2pi-theta |
| 120 | + theta_prime = (sympy.pi - sign * sympy.pi) + sign * theta |
| 121 | + |
| 122 | + phi = sympy.asin(np.sqrt(2) * sympy.sin(theta_prime / 4)) |
| 123 | + xi = sympy.atan(sympy.tan(phi) / np.sqrt(2)) |
| 124 | + |
| 125 | + yield ops.rz(sign * 0.5 * theta_prime).on(a) |
| 126 | + yield ops.rz(sign * 0.5 * theta_prime).on(b) |
| 127 | + yield ops.rx(xi).on(a) |
| 128 | + yield ops.X(b) ** (-sign * 0.5) |
| 129 | + yield _sqrt_iswap_inv(a, b, use_sqrt_iswap_inv) |
| 130 | + yield ops.rx(-2 * phi).on(a) |
| 131 | + yield ops.Z(a) |
| 132 | + yield _sqrt_iswap_inv(a, b, use_sqrt_iswap_inv) |
| 133 | + yield ops.Z(a) |
| 134 | + yield ops.rx(xi).on(a) |
| 135 | + yield ops.X(b) ** (sign * 0.5) |
| 136 | + |
| 137 | + |
| 138 | +def _swap_symbols_to_sqrt_iswap( |
| 139 | + a: 'cirq.Qid', b: 'cirq.Qid', turns: 'cirq.TParamVal', use_sqrt_iswap_inv: bool = True |
| 140 | +): |
| 141 | + """Implements `cirq.SWAP(a, b) ** turns` using two √iSWAPs and single qubit rotations. |
| 142 | +
|
| 143 | + Output unitary: |
| 144 | + [[1, 0, 0, 0], |
| 145 | + [0, g·c, -i·g·s, 0], |
| 146 | + [0, -i·g·s, g·c, 0], |
| 147 | + [0, 0, 0, 1]] |
| 148 | + where: |
| 149 | + c = cos(π·t/2), s = sin(π·t/2), g = exp(i·π·t/2). |
| 150 | +
|
| 151 | + Args: |
| 152 | + a: The first qubit. |
| 153 | + b: The second qubit. |
| 154 | + turns: The rotational angle (t) that specifies the gate, where |
| 155 | + c = cos(π·t/2), s = sin(π·t/2), g = exp(i·π·t/2). |
| 156 | + use_sqrt_iswap_inv: If True, `cirq.SQRT_ISWAP_INV` is used instead of `cirq.SQRT_ISWAP`. |
| 157 | +
|
| 158 | + Yields: |
| 159 | + A `cirq.OP_TREE` representing the decomposition. |
| 160 | + """ |
| 161 | + yield ops.Z(a) ** 1.25 |
| 162 | + yield ops.Z(b) ** -0.25 |
| 163 | + yield _sqrt_iswap_inv(a, b, use_sqrt_iswap_inv) |
| 164 | + yield ops.Z(a) ** (-turns / 2 + 1) |
| 165 | + yield ops.Z(b) ** (turns / 2) |
| 166 | + yield _sqrt_iswap_inv(a, b, use_sqrt_iswap_inv) |
| 167 | + yield ops.Z(a) ** (turns / 2 - 0.25) |
| 168 | + yield ops.Z(b) ** (turns / 2 + 0.25) |
| 169 | + yield _cphase_symbols_to_sqrt_iswap(a, b, -turns, use_sqrt_iswap_inv) |
| 170 | + |
| 171 | + |
| 172 | +def _iswap_symbols_to_sqrt_iswap( |
| 173 | + a: 'cirq.Qid', b: 'cirq.Qid', turns: 'cirq.TParamVal', use_sqrt_iswap_inv: bool = True |
| 174 | +): |
| 175 | + """Implements `cirq.ISWAP(a, b) ** turns` using two √iSWAPs and single qubit rotations. |
| 176 | +
|
| 177 | + Output unitary: |
| 178 | + [[1 0 0 0], |
| 179 | + [0 c is 0], |
| 180 | + [0 is c 0], |
| 181 | + [0 0 0 1]] |
| 182 | + where c = cos(π·t/2), s = sin(π·t/2). |
| 183 | +
|
| 184 | + Args: |
| 185 | + a: The first qubit. |
| 186 | + b: The second qubit. |
| 187 | + turns: The rotational angle (t) that specifies the gate, where |
| 188 | + c = cos(π·t/2), s = sin(π·t/2). |
| 189 | + use_sqrt_iswap_inv: If True, `cirq.SQRT_ISWAP_INV` is used instead of `cirq.SQRT_ISWAP`. |
| 190 | +
|
| 191 | + Yields: |
| 192 | + A `cirq.OP_TREE` representing the decomposition. |
| 193 | + """ |
| 194 | + yield ops.Z(a) ** 0.75 |
| 195 | + yield ops.Z(b) ** 0.25 |
| 196 | + yield _sqrt_iswap_inv(a, b, use_sqrt_iswap_inv) |
| 197 | + yield ops.Z(a) ** (-turns / 2 + 1) |
| 198 | + yield ops.Z(b) ** (turns / 2) |
| 199 | + yield _sqrt_iswap_inv(a, b, use_sqrt_iswap_inv) |
| 200 | + yield ops.Z(a) ** 0.25 |
| 201 | + yield ops.Z(b) ** -0.25 |
| 202 | + |
| 203 | + |
| 204 | +def _fsim_symbols_to_sqrt_iswap( |
| 205 | + a: 'cirq.Qid', |
| 206 | + b: 'cirq.Qid', |
| 207 | + theta: 'cirq.TParamVal', |
| 208 | + phi: 'cirq.TParamVal', |
| 209 | + use_sqrt_iswap_inv: bool = True, |
| 210 | +): |
| 211 | + """Implements `cirq.FSimGate(theta, phi)(a, b)` using two √iSWAPs and single qubit rotations. |
| 212 | +
|
| 213 | + FSimGate(θ, φ) = ISWAP**(-2θ/π) CZPowGate(exponent=-φ/π) |
| 214 | +
|
| 215 | + Args: |
| 216 | + a: The first qubit. |
| 217 | + b: The second qubit. |
| 218 | + theta: Swap angle on the ``|01⟩`` ``|10⟩`` subspace, in radians. |
| 219 | + phi: Controlled phase angle, in radians. |
| 220 | + use_sqrt_iswap_inv: If True, `cirq.SQRT_ISWAP_INV` is used instead of `cirq.SQRT_ISWAP`. |
| 221 | +
|
| 222 | + Yields: |
| 223 | + A `cirq.OP_TREE` representing the decomposition. |
| 224 | + """ |
| 225 | + if theta != 0.0: |
| 226 | + yield _iswap_symbols_to_sqrt_iswap(a, b, -2 * theta / np.pi, use_sqrt_iswap_inv) |
| 227 | + if phi != 0.0: |
| 228 | + yield _cphase_symbols_to_sqrt_iswap(a, b, -phi / np.pi, use_sqrt_iswap_inv) |
| 229 | + |
| 230 | + |
35 | 231 | def two_qubit_matrix_to_sqrt_iswap_operations(
|
36 | 232 | q0: 'cirq.Qid',
|
37 | 233 | q1: 'cirq.Qid',
|
|
0 commit comments