def default_pass_manager(transpile_config): """ The default pass manager that maps to the coupling map. Args: transpile_config (TranspileConfig) Returns: PassManager: A pass manager to map and optimize. """ basis_gates = transpile_config.basis_gates coupling_map = transpile_config.coupling_map initial_layout = transpile_config.initial_layout seed_transpiler = transpile_config.seed_transpiler pass_manager = PassManager() pass_manager.append(SetLayout(initial_layout)) pass_manager.append(Unroller(basis_gates)) # Use the trivial layout if no layout is found pass_manager.append( TrivialLayout(coupling_map), condition=lambda property_set: not property_set['layout']) # if the circuit and layout already satisfy the coupling_constraints, use that layout # otherwise layout on the most densely connected physical qubit subset pass_manager.append(CheckMap(coupling_map)) pass_manager.append( DenseLayout(coupling_map), condition=lambda property_set: not property_set['is_swap_mapped']) # Extend the the dag/layout with ancillas using the full coupling map pass_manager.append(FullAncillaAllocation(coupling_map)) pass_manager.append(EnlargeWithAncilla()) # Circuit must only contain 1- or 2-qubit interactions for swapper to work pass_manager.append(Unroll3qOrMore()) # Swap mapper pass_manager.append(BarrierBeforeFinalMeasurements()) pass_manager.append( LegacySwap(coupling_map, trials=20, seed=seed_transpiler)) # Expand swaps pass_manager.append(Decompose(SwapGate)) # Change CX directions pass_manager.append(CXDirection(coupling_map)) # Simplify single qubit gates and CXs simplification_passes = [ Optimize1qGates(), CXCancellation(), RemoveResetInZeroState() ] pass_manager.append( simplification_passes + [Depth(), FixedPoint('depth')], do_while=lambda property_set: not property_set['depth_fixed_point']) return pass_manager
def level_0_pass_manager(transpile_config): """ Level 0 pass manager: no explicit optimization other than mapping to backend. This pass manager applies the user-given initial layout. If none is given, a trivial layout consisting of mapping the i-th virtual qubit to the i-th physical qubit is used. Any unused physical qubit is allocated as ancilla space. The pass manager then unrolls the circuit to the desired basis, and transforms the circuit to match the coupling map. Finally, extra resets are removed. Note: in simulators where coupling_map=None, only the unrolling and optimization stages are done. Args: transpile_config (TranspileConfig) Returns: PassManager: a level 0 pass manager. """ basis_gates = transpile_config.basis_gates coupling_map = transpile_config.coupling_map initial_layout = transpile_config.initial_layout seed_transpiler = transpile_config.seed_transpiler # 1. Use trivial layout if no layout given _given_layout = SetLayout(initial_layout) def _choose_layout_condition(property_set): return not property_set['layout'] _choose_layout = TrivialLayout(coupling_map) # 2. Extend dag/layout with ancillas using the full coupling map _embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla()] # 3. Unroll to the basis _unroll = Unroller(basis_gates) # 4. Swap to fit the coupling map _swap_check = CheckMap(coupling_map) def _swap_condition(property_set): return not property_set['is_swap_mapped'] _swap = [ BarrierBeforeFinalMeasurements(), LegacySwap(coupling_map, trials=20, seed=seed_transpiler), Decompose(SwapGate) ] # 5. Fix any bad CX directions # _direction_check = CheckCXDirection(coupling_map) # TODO def _direction_condition(property_set): return not property_set['is_direction_mapped'] _direction = [CXDirection(coupling_map)] # 6. Remove zero-state reset _reset = RemoveResetInZeroState() pm0 = PassManager() if coupling_map: pm0.append(_given_layout) pm0.append(_choose_layout, condition=_choose_layout_condition) pm0.append(_embed) pm0.append(_unroll) if coupling_map: pm0.append(_swap_check) pm0.append(_swap, condition=_swap_condition) # pm0.append(_direction_check) # TODO pm0.append(_direction, condition=_direction_condition) pm0.append(_reset) return pm0
def level_1_pass_manager(transpile_config): """ Level 1 pass manager: light optimization by simple adjacent gate collapsing This pass manager applies the user-given initial layout. If none is given, and a trivial layout (i-th virtual -> i-th physical) makes the circuit fit the coupling map, that is used. Otherwise, the circuit is mapped to the most densely connected coupling subgraph, and swaps are inserted to map. Any unused physical qubit is allocated as ancilla space. The pass manager then unrolls the circuit to the desired basis, and transforms the circuit to match the coupling map. Finally, optimizations in the form of adjacent gate collapse and redundant reset removal are performed. Note: in simulators where coupling_map=None, only the unrolling and optimization stages are done. Args: transpile_config (TranspileConfig) Returns: PassManager: a level 1 pass manager. """ basis_gates = transpile_config.basis_gates coupling_map = transpile_config.coupling_map initial_layout = transpile_config.initial_layout seed_transpiler = transpile_config.seed_transpiler # 1. Use trivial layout if no layout given _given_layout = SetLayout(initial_layout) def _choose_layout_condition(property_set): return not property_set['layout'] _choose_layout = TrivialLayout(coupling_map) # 2. Use a better layout on densely connected qubits, if circuit needs swaps _layout_check = CheckMap(coupling_map) def _improve_layout_condition(property_set): return not property_set['is_swap_mapped'] _improve_layout = DenseLayout(coupling_map) # 2. Extend dag/layout with ancillas using the full coupling map _embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla()] # 3. Unroll to the basis _unroll = Unroller(basis_gates) # 4. Swap to fit the coupling map _swap_check = CheckMap(coupling_map) def _swap_condition(property_set): return not property_set['is_swap_mapped'] _swap = [BarrierBeforeFinalMeasurements(), LegacySwap(coupling_map, trials=20, seed=seed_transpiler), Decompose(SwapGate)] # 5. Fix any bad CX directions # _direction_check = CheckCXDirection(coupling_map) # TODO def _direction_condition(property_set): return not property_set['is_direction_mapped'] _direction = [CXDirection(coupling_map)] # 6. Remove zero-state reset _reset = RemoveResetInZeroState() # 7. Merge 1q rotations and cancel CNOT gates iteratively until no more change in depth _depth_check = [Depth(), FixedPoint('depth')] def _opt_control(property_set): return not property_set['depth_fixed_point'] _opt = [Optimize1qGates(), CXCancellation()] pm1 = PassManager() if coupling_map: pm1.append(_given_layout) pm1.append(_choose_layout, condition=_choose_layout_condition) pm1.append(_layout_check) pm1.append(_improve_layout, condition=_improve_layout_condition) pm1.append(_embed) pm1.append(_unroll) if coupling_map: pm1.append(_swap_check) pm1.append(_swap, condition=_swap_condition) # pm1.append(_direction_check) # TODO pm1.append(_direction, condition=_direction_condition) pm1.append(_reset) pm1.append(_depth_check + _opt, do_while=_opt_control) return pm1
def level_3_pass_manager(transpile_config): """ Level 3 pass manager: heavy optimization by noise adaptive qubit mapping and gate cancellation using commutativity rules and unitary synthesis. This pass manager applies the user-given initial layout. If none is given, and device calibration information is available, the circuit is mapped to the qubits with best readouts and to CX gates with highest fidelity. Otherwise, a layout on the most densely connected qubits is used. The pass manager then transforms the circuit to match the coupling constraints. It is then unrolled to the basis, and any flipped cx directions are fixed. Finally, optimizations in the form of commutative gate cancellation, resynthesis of two-qubit unitary blocks, and redundant reset removal are performed. Note: in simulators where coupling_map=None, only the unrolling and optimization stages are done. Args: transpile_config (TranspileConfig) Returns: PassManager: a level 3 pass manager. """ basis_gates = transpile_config.basis_gates coupling_map = transpile_config.coupling_map initial_layout = transpile_config.initial_layout seed_transpiler = transpile_config.seed_transpiler backend_properties = transpile_config.backend_properties # 1. Layout on good qubits if calibration info available, otherwise on dense links _given_layout = SetLayout(initial_layout) def _choose_layout_condition(property_set): return not property_set['layout'] _choose_layout = DenseLayout(coupling_map) if backend_properties: _choose_layout = NoiseAdaptiveLayout(backend_properties) # 2. Extend dag/layout with ancillas using the full coupling map _embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla()] # 3. Unroll to 1q or 2q gates, swap to fit the coupling map _swap_check = CheckMap(coupling_map) def _swap_condition(property_set): return not property_set['is_swap_mapped'] _swap = [ BarrierBeforeFinalMeasurements(), Unroll3qOrMore(), LegacySwap(coupling_map, trials=20, seed=seed_transpiler) ] # 4. Unroll to the basis _unroll = Unroller(basis_gates) # 5. 1q rotation merge and commutative cancellation iteratively until no more change in depth _depth_check = [Depth(), FixedPoint('depth')] def _opt_control(property_set): return not property_set['depth_fixed_point'] _opt = [ RemoveResetInZeroState(), Collect2qBlocks(), ConsolidateBlocks(), Unroller(basis_gates), # unroll unitaries Optimize1qGates(), CommutativeCancellation(), OptimizeSwapBeforeMeasure(), RemoveDiagonalGatesBeforeMeasure() ] if coupling_map: _opt.append(CXDirection(coupling_map)) # if a coupling map has been provided, match coupling pm3 = PassManager() if coupling_map: pm3.append(_given_layout) pm3.append(_choose_layout, condition=_choose_layout_condition) pm3.append(_embed) pm3.append(_unroll) if coupling_map: pm3.append(_swap_check) pm3.append(_swap, condition=_swap_condition) pm3.append(_depth_check + _opt, do_while=_opt_control) return pm3
def level_2_pass_manager(transpile_config): """ Level 2 pass manager: medium optimization by noise adaptive qubit mapping and gate cancellation using commutativity rules. This pass manager applies the user-given initial layout. If none is given, and device calibration information is available, the circuit is mapped to the qubits with best readouts and to CX gates with highest fidelity. Otherwise, a layout on the most densely connected qubits is used. The pass manager then transforms the circuit to match the coupling constraints. It is then unrolled to the basis, and any flipped cx directions are fixed. Finally, optimizations in the form of commutative gate cancellation and redundant reset removal are performed. Note: in simulators where coupling_map=None, only the unrolling and optimization stages are done. Args: transpile_config (TranspileConfig) Returns: PassManager: a level 2 pass manager. """ basis_gates = transpile_config.basis_gates coupling_map = transpile_config.coupling_map initial_layout = transpile_config.initial_layout seed_transpiler = transpile_config.seed_transpiler backend_properties = transpile_config.backend_properties # 1. Layout on good qubits if calibration info available, otherwise on dense links _given_layout = SetLayout(initial_layout) def _choose_layout_condition(property_set): return not property_set['layout'] _choose_layout = DenseLayout(coupling_map) if backend_properties: _choose_layout = NoiseAdaptiveLayout(backend_properties) # 2. Extend dag/layout with ancillas using the full coupling map _embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla()] # 3. Unroll to 1q or 2q gates, swap to fit the coupling map _swap_check = CheckMap(coupling_map) def _swap_condition(property_set): return not property_set['is_swap_mapped'] _swap = [ BarrierBeforeFinalMeasurements(), Unroll3qOrMore(), LegacySwap(coupling_map), Decompose(SwapGate) ] # 4. Unroll to the basis _unroll = Unroller(basis_gates) # 5. Fix any bad CX directions # _direction_check = CheckCXDirection(coupling_map) # TODO def _direction_condition(property_set): return not property_set['is_direction_mapped'] _direction = [CXDirection(coupling_map)] # 6. Remove zero-state reset _reset = RemoveResetInZeroState() # 7. 1q rotation merge and commutative cancellation iteratively until no more change in depth _depth_check = [Depth(), FixedPoint('depth')] def _opt_control(property_set): return not property_set['depth_fixed_point'] _opt = [Optimize1qGates(), CommutativeCancellation()] pm2 = PassManager() if coupling_map: pm2.append(_given_layout) pm2.append(_choose_layout, condition=_choose_layout_condition) pm2.append(_embed) pm2.append(_unroll) if coupling_map: pm2.append(_swap_check) pm2.append(_swap, condition=_swap_condition) # pm2.append(_direction_check) # TODO pm2.append(_direction, condition=_direction_condition) pm2.append(_reset) pm2.append(_depth_check + _opt, do_while=_opt_control) return pm2