|
14 | 14 |
|
15 | 15 | import os
|
16 | 16 |
|
| 17 | +from qiskit.circuit import Instruction |
| 18 | +from qiskit.transpiler.passes.optimization.split_2q_unitaries import Split2QUnitaries |
17 | 19 | from qiskit.transpiler.passmanager import PassManager
|
18 | 20 | from qiskit.transpiler.exceptions import TranspilerError
|
19 | 21 | from qiskit.transpiler.passes import BasicSwap
|
|
64 | 66 | CYGate,
|
65 | 67 | SXGate,
|
66 | 68 | SXdgGate,
|
| 69 | + get_standard_gate_name_mapping, |
67 | 70 | )
|
68 | 71 | from qiskit.utils.parallel import CPU_COUNT
|
69 | 72 | from qiskit import user_config
|
70 | 73 |
|
71 | 74 | CONFIG = user_config.get_config()
|
72 | 75 |
|
| 76 | +_discrete_skipped_ops = { |
| 77 | + "delay", |
| 78 | + "reset", |
| 79 | + "measure", |
| 80 | + "switch_case", |
| 81 | + "if_else", |
| 82 | + "for_loop", |
| 83 | + "while_loop", |
| 84 | +} |
| 85 | + |
73 | 86 |
|
74 | 87 | class DefaultInitPassManager(PassManagerStagePlugin):
|
75 | 88 | """Plugin class for default init stage."""
|
@@ -160,6 +173,58 @@ def pass_manager(self, pass_manager_config, optimization_level=None) -> PassMana
|
160 | 173 | )
|
161 | 174 | )
|
162 | 175 | init.append(CommutativeCancellation())
|
| 176 | + # skip peephole optimization before routing if target basis gate set is discrete, |
| 177 | + # i.e. only consists of Cliffords that an user might want to keep |
| 178 | + # use rz, sx, x, cx as basis, rely on physical optimziation to fix everything later one |
| 179 | + stdgates = get_standard_gate_name_mapping() |
| 180 | + |
| 181 | + def _is_one_op_non_discrete(ops): |
| 182 | + """Checks if one operation in `ops` is not discrete, i.e. is parameterizable |
| 183 | + Args: |
| 184 | + ops (List(Operation)): list of operations to check |
| 185 | + Returns |
| 186 | + True if at least one operation in `ops` is not discrete, False otherwise |
| 187 | + """ |
| 188 | + found_one_continuous_gate = False |
| 189 | + for op in ops: |
| 190 | + if isinstance(op, str): |
| 191 | + if op in _discrete_skipped_ops: |
| 192 | + continue |
| 193 | + op = stdgates.get(op, None) |
| 194 | + |
| 195 | + if op is not None and op.name in _discrete_skipped_ops: |
| 196 | + continue |
| 197 | + |
| 198 | + if op is None or not isinstance(op, Instruction): |
| 199 | + return False |
| 200 | + |
| 201 | + if len(op.params) > 0: |
| 202 | + found_one_continuous_gate = True |
| 203 | + return found_one_continuous_gate |
| 204 | + |
| 205 | + target = pass_manager_config.target |
| 206 | + basis = pass_manager_config.basis_gates |
| 207 | + # consolidate gates before routing if the user did not specify a discrete basis gate, i.e. |
| 208 | + # * no target or basis gate set has been specified |
| 209 | + # * target has been specified, and we have one non-discrete gate in the target's spec |
| 210 | + # * basis gates have been specified, and we have one non-discrete gate in that set |
| 211 | + do_consolidate_blocks_init = target is None and basis is None |
| 212 | + do_consolidate_blocks_init |= target is not None and _is_one_op_non_discrete( |
| 213 | + target.operations |
| 214 | + ) |
| 215 | + do_consolidate_blocks_init |= basis is not None and _is_one_op_non_discrete(basis) |
| 216 | + |
| 217 | + if do_consolidate_blocks_init: |
| 218 | + init.append(Collect2qBlocks()) |
| 219 | + init.append(ConsolidateBlocks()) |
| 220 | + # If approximation degree is None that indicates a request to approximate up to the |
| 221 | + # error rates in the target. However, in the init stage we don't yet know the target |
| 222 | + # qubits being used to figure out the fidelity so just use the default fidelity parameter |
| 223 | + # in this case. |
| 224 | + if pass_manager_config.approximation_degree is not None: |
| 225 | + init.append(Split2QUnitaries(pass_manager_config.approximation_degree)) |
| 226 | + else: |
| 227 | + init.append(Split2QUnitaries()) |
163 | 228 | else:
|
164 | 229 | raise TranspilerError(f"Invalid optimization level {optimization_level}")
|
165 | 230 | return init
|
|
0 commit comments