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))
Пример #2
0
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
Пример #3
0
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)