def test_overlapping_block_and_run(self): """Test that an overlapping block and run only consolidate once""" # ┌───┐┌───┐┌─────┐ # q_0: ┤ H ├┤ T ├┤ Sdg ├──■──────────────────────── # └───┘└───┘└─────┘┌─┴─┐┌───┐┌─────┐┌───┐┌───┐ # q_1: ─────────────────┤ X ├┤ T ├┤ Sdg ├┤ Z ├┤ I ├ # └───┘└───┘└─────┘└───┘└───┘ qc = QuantumCircuit(2) qc.h(0) qc.t(0) qc.sdg(0) qc.cx(0, 1) qc.t(1) qc.sdg(1) qc.z(1) qc.i(1) pass_manager = PassManager() pass_manager.append(Collect2qBlocks()) pass_manager.append(Collect1qRuns()) pass_manager.append(ConsolidateBlocks(force_consolidate=True)) result = pass_manager.run(qc) expected = Operator(qc) # Assert output circuit is a single unitary gate equivalent to # unitary of original circuit self.assertEqual(len(result), 1) self.assertIsInstance(result.data[0][0], UnitaryGate) self.assertTrue(np.allclose(result.data[0][0].to_matrix(), expected))
def level_0_pass_manager( pass_manager_config: PassManagerConfig) -> PassManager: """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. Note: In simulators where ``coupling_map=None``, only the unrolling and optimization stages are done. Args: pass_manager_config: configuration of the pass manager. Returns: a level 0 pass manager. Raises: TranspilerError: if the passmanager config is invalid. """ basis_gates = pass_manager_config.basis_gates inst_map = pass_manager_config.inst_map coupling_map = pass_manager_config.coupling_map initial_layout = pass_manager_config.initial_layout layout_method = pass_manager_config.layout_method or "trivial" routing_method = pass_manager_config.routing_method or "stochastic" translation_method = pass_manager_config.translation_method or "translator" scheduling_method = pass_manager_config.scheduling_method instruction_durations = pass_manager_config.instruction_durations seed_transpiler = pass_manager_config.seed_transpiler backend_properties = pass_manager_config.backend_properties approximation_degree = pass_manager_config.approximation_degree timing_constraints = pass_manager_config.timing_constraints or TimingConstraints( ) unitary_synthesis_method = pass_manager_config.unitary_synthesis_method unitary_synthesis_plugin_config = pass_manager_config.unitary_synthesis_plugin_config target = pass_manager_config.target # 1. Decompose so only 1-qubit and 2-qubit gates remain _unroll3q = [ # Use unitary synthesis for basis aware decomposition of UnitaryGates UnitarySynthesis( basis_gates, approximation_degree=approximation_degree, method=unitary_synthesis_method, min_qubits=3, plugin_config=unitary_synthesis_plugin_config, ), Unroll3qOrMore(), ] # 2. Choose an initial layout if not set by user (default: trivial layout) _given_layout = SetLayout(initial_layout) def _choose_layout_condition(property_set): return not property_set["layout"] if layout_method == "trivial": _choose_layout = TrivialLayout(coupling_map) elif layout_method == "dense": _choose_layout = DenseLayout(coupling_map, backend_properties) elif layout_method == "noise_adaptive": _choose_layout = NoiseAdaptiveLayout(backend_properties) elif layout_method == "sabre": _choose_layout = SabreLayout(coupling_map, max_iterations=1, seed=seed_transpiler) else: raise TranspilerError("Invalid layout method %s." % layout_method) # 3. Extend dag/layout with ancillas using the full coupling map _embed = [ FullAncillaAllocation(coupling_map), EnlargeWithAncilla(), ApplyLayout() ] # 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()] if routing_method == "basic": _swap += [BasicSwap(coupling_map)] elif routing_method == "stochastic": _swap += [ StochasticSwap(coupling_map, trials=20, seed=seed_transpiler) ] elif routing_method == "lookahead": _swap += [LookaheadSwap(coupling_map, search_depth=2, search_width=2)] elif routing_method == "sabre": _swap += [ SabreSwap(coupling_map, heuristic="basic", seed=seed_transpiler) ] elif routing_method == "none": _swap += [ Error( msg= ("No routing method selected, but circuit is not routed to device. " "CheckMap Error: {check_map_msg}"), action="raise", ) ] else: raise TranspilerError("Invalid routing method %s." % routing_method) # 5. Unroll to the basis if translation_method == "unroller": _unroll = [Unroller(basis_gates)] elif translation_method == "translator": from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel _unroll = [ UnitarySynthesis( basis_gates, approximation_degree=approximation_degree, coupling_map=coupling_map, backend_props=backend_properties, method=unitary_synthesis_method, plugin_config=unitary_synthesis_plugin_config, ), UnrollCustomDefinitions(sel, basis_gates), BasisTranslator(sel, basis_gates, target), ] elif translation_method == "synthesis": _unroll = [ UnitarySynthesis( basis_gates, approximation_degree=approximation_degree, coupling_map=coupling_map, backend_props=backend_properties, method=unitary_synthesis_method, min_qubits=3, plugin_config=unitary_synthesis_plugin_config, ), Unroll3qOrMore(), Collect2qBlocks(), Collect1qRuns(), ConsolidateBlocks(basis_gates=basis_gates), UnitarySynthesis( basis_gates, approximation_degree=approximation_degree, coupling_map=coupling_map, backend_props=backend_properties, method=unitary_synthesis_method, plugin_config=unitary_synthesis_plugin_config, ), ] else: raise TranspilerError("Invalid translation method %s." % translation_method) # 6. Fix any bad CX directions _direction_check = [CheckGateDirection(coupling_map, target)] def _direction_condition(property_set): return not property_set["is_direction_mapped"] _direction = [GateDirection(coupling_map, target)] # 7. Unify all durations (either SI, or convert to dt if known) # Schedule the circuit only when scheduling_method is supplied _time_unit_setup = [ContainsInstruction("delay")] _time_unit_conversion = [TimeUnitConversion(instruction_durations)] def _contains_delay(property_set): return property_set["contains_delay"] _scheduling = [] if scheduling_method: _scheduling += _time_unit_conversion if scheduling_method in {"alap", "as_late_as_possible"}: _scheduling += [ALAPSchedule(instruction_durations)] elif scheduling_method in {"asap", "as_soon_as_possible"}: _scheduling += [ASAPSchedule(instruction_durations)] else: raise TranspilerError("Invalid scheduling method %s." % scheduling_method) # 8. Call measure alignment. Should come after scheduling. if (timing_constraints.granularity != 1 or timing_constraints.min_length != 1 or timing_constraints.acquire_alignment != 1): _alignments = [ ValidatePulseGates(granularity=timing_constraints.granularity, min_length=timing_constraints.min_length), AlignMeasures(alignment=timing_constraints.acquire_alignment), ] else: _alignments = [] # Build pass manager pm0 = PassManager() if coupling_map or initial_layout: pm0.append(_given_layout) pm0.append(_unroll3q) pm0.append(_choose_layout, condition=_choose_layout_condition) pm0.append(_embed) pm0.append(_swap_check) pm0.append(_swap, condition=_swap_condition) pm0.append(_unroll) if (coupling_map and not coupling_map.is_symmetric) or ( target is not None and target.get_non_global_operation_names(strict_direction=True)): pm0.append(_direction_check) pm0.append(_direction, condition=_direction_condition) pm0.append(_unroll) if inst_map and inst_map.has_custom_gate(): pm0.append(PulseGates(inst_map=inst_map)) if scheduling_method: pm0.append(_scheduling) elif instruction_durations: pm0.append(_time_unit_setup) pm0.append(_time_unit_conversion, condition=_contains_delay) pm0.append(_alignments) return pm0
def generate_translation_passmanager( target, basis_gates=None, method="translator", approximation_degree=None, coupling_map=None, backend_props=None, unitary_synthesis_method="default", unitary_synthesis_plugin_config=None, ): """Generate a basis translation :class:`~qiskit.transpiler.PassManager` Args: target (Target): the :class:`~.Target` object representing the backend basis_gates (list): A list of str gate names that represent the basis gates on the backend target method (str): The basis translation method to use approximation_degree (float): The heuristic approximation degree to use. Can be between 0 and 1. coupling_map (CouplingMap): the coupling map of the backend in case synthesis is done on a physical circuit. The directionality of the coupling_map will be taken into account if pulse_optimize is True/None and natural_direction is True/None. unitary_synthesis_plugin_config (dict): The optional dictionary plugin configuration, this is plugin specific refer to the specified plugin's documenation for how to use. backend_props (BackendProperties): Properties of a backend to synthesize for (e.g. gate fidelities). unitary_synthesis_method (str): The unitary synthesis method to use Returns: PassManager: The basis translation pass manager Raises: TranspilerError: If the ``method`` kwarg is not a valid value """ if method == "unroller": unroll = [Unroller(basis_gates)] elif method == "translator": unroll = [ # Use unitary synthesis for basis aware decomposition of # UnitaryGates before custom unrolling UnitarySynthesis( basis_gates, approximation_degree=approximation_degree, coupling_map=coupling_map, backend_props=backend_props, plugin_config=unitary_synthesis_plugin_config, method=unitary_synthesis_method, target=target, ), HighLevelSynthesis(), UnrollCustomDefinitions(sel, basis_gates), BasisTranslator(sel, basis_gates, target), ] elif method == "synthesis": unroll = [ # # Use unitary synthesis for basis aware decomposition of # UnitaryGates > 2q before collection UnitarySynthesis( basis_gates, approximation_degree=approximation_degree, coupling_map=coupling_map, backend_props=backend_props, plugin_config=unitary_synthesis_plugin_config, method=unitary_synthesis_method, min_qubits=3, target=target, ), HighLevelSynthesis(), Unroll3qOrMore(target=target, basis_gates=basis_gates), Collect2qBlocks(), Collect1qRuns(), ConsolidateBlocks(basis_gates=basis_gates, target=target), UnitarySynthesis( basis_gates=basis_gates, approximation_degree=approximation_degree, coupling_map=coupling_map, backend_props=backend_props, plugin_config=unitary_synthesis_plugin_config, method=unitary_synthesis_method, target=target, ), HighLevelSynthesis(), ] else: raise TranspilerError("Invalid translation method %s." % method) return PassManager(unroll)