|
14 | 14 |
|
15 | 15 | """Transformer passes to combine adjacent single-qubit rotations."""
|
16 | 16 |
|
17 |
| -from typing import Optional, TYPE_CHECKING |
| 17 | +import enum |
| 18 | +import warnings |
| 19 | +from typing import Optional, TYPE_CHECKING |
| 20 | + |
18 | 21 |
|
19 | 22 | from cirq import circuits, ops, protocols
|
| 23 | +from cirq.study import sweepable |
20 | 24 | from cirq.transformers.analytical_decompositions import single_qubit_decompositions
|
21 | 25 | from cirq.transformers import transformer_api, transformer_primitives, merge_k_qubit_gates
|
22 | 26 |
|
@@ -152,3 +156,87 @@ def merge_func(m1: 'cirq.Moment', m2: 'cirq.Moment') -> Optional['cirq.Moment']:
|
152 | 156 | deep=context.deep if context else False,
|
153 | 157 | tags_to_ignore=tuple(tags_to_ignore),
|
154 | 158 | ).unfreeze(copy=False)
|
| 159 | + |
| 160 | + |
| 161 | +@transformer_api.transformer |
| 162 | +def merge_into_symbolized_phxz( |
| 163 | + circuit: 'cirq.AbstractCircuit', |
| 164 | + *, |
| 165 | + context: Optional['cirq.TransformerContext'] = None, |
| 166 | + sweeps: Optional['sweepable.Sweepable'] = None, |
| 167 | + atol: float = 1e-8, |
| 168 | +) -> 'cirq.Circuit': |
| 169 | + """Merge consecutive single qubit gates into connected symbolized PhasedXZ gates. |
| 170 | +
|
| 171 | + Specifically, if at least one of the consecutive gates is symbolized, then the merged gate |
| 172 | + will be a symbolized gate. |
| 173 | +
|
| 174 | + e.g., X-Y-H-phxz(sa, sx, sz) ---transform---> phxz(sa, sx, sz) |
| 175 | +
|
| 176 | + Note, we only consider merging non-parameterized gates to symbolized phxz with |
| 177 | + 3 degrees of freedom, meaning that gates like Z^exp_symbol will be considered non-mergable. |
| 178 | +
|
| 179 | + Args: |
| 180 | + circuit: Input circuit to transform. It will not be modified. |
| 181 | + sweeps: Sweeps of the symbols in the input circuit, updated Sweeps will be returned |
| 182 | + based on the transformation. |
| 183 | + context: `cirq.TransformerContext` storing common configurable options for transformers. |
| 184 | + atol: Absolute tolerance to angle error. Larger values allow more negligible gates to be |
| 185 | + dropped, smaller values increase accuracy. |
| 186 | +
|
| 187 | + Returns: |
| 188 | + Copy of the transformed input circuit. |
| 189 | + """ |
| 190 | + |
| 191 | + # TODO(#6994): support returning update sweeps when sweeps are provided. |
| 192 | + if sweeps is not None: |
| 193 | + raise NotImplementedError("To be supported in #6994.") |
| 194 | + |
| 195 | + if not protocols.is_parameterized(circuit): |
| 196 | + warnings.warn( |
| 197 | + "Expect parameterized circuits. " |
| 198 | + "Please use cirq.merge_single_qubit_gates_to_phxz instead.", |
| 199 | + UserWarning, |
| 200 | + ) |
| 201 | + return merge_single_qubit_gates_to_phxz(circuit, context=context, atol=atol) |
| 202 | + |
| 203 | + # Merge all non parameterized single qubit gates first. |
| 204 | + circuit = merge_single_qubit_gates_to_phxz(circuit, context=context, atol=atol) |
| 205 | + |
| 206 | + def _merge_func(op1: 'cirq.Operation', op2: 'cirq.Operation'): |
| 207 | + |
| 208 | + class _MergeGateType(enum.Enum): |
| 209 | + MERAGABLE_NON_PARAMETERIZED = 0 |
| 210 | + MERAGABLE_PARAMETERIZED_PHXZ = 1 |
| 211 | + NON_MERGEABLE = 2 |
| 212 | + |
| 213 | + def _categorize(op: 'cirq.Operation') -> _MergeGateType: |
| 214 | + if protocols.has_unitary(op) and protocols.num_qubits(op) == 1: |
| 215 | + return _MergeGateType.MERAGABLE_NON_PARAMETERIZED |
| 216 | + if isinstance(op.gate, ops.PhasedXZGate) and protocols.is_parameterized(op): |
| 217 | + return _MergeGateType.MERAGABLE_PARAMETERIZED_PHXZ |
| 218 | + return _MergeGateType.NON_MERGEABLE |
| 219 | + |
| 220 | + merge_type1 = _categorize(op1) |
| 221 | + merge_type2 = _categorize(op2) |
| 222 | + |
| 223 | + if ( |
| 224 | + merge_type1 == _MergeGateType.NON_MERGEABLE |
| 225 | + or merge_type2 == _MergeGateType.NON_MERGEABLE |
| 226 | + ): |
| 227 | + return None |
| 228 | + |
| 229 | + # absorb the non-parameterized gate into the parameterized gate. |
| 230 | + if merge_type1 == _MergeGateType.MERAGABLE_PARAMETERIZED_PHXZ: |
| 231 | + return op1 |
| 232 | + if merge_type2 == _MergeGateType.MERAGABLE_PARAMETERIZED_PHXZ: |
| 233 | + return op2 |
| 234 | + |
| 235 | + return None # pragma: no cover |
| 236 | + |
| 237 | + return transformer_primitives.merge_operations( |
| 238 | + circuit, |
| 239 | + _merge_func, |
| 240 | + deep=context.deep if context else False, |
| 241 | + tags_to_ignore=context.tags_to_ignore if context else (), |
| 242 | + ).unfreeze() |
0 commit comments