# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License
"""Compile a circuit."""
from __future__ import annotations
from typing import TYPE_CHECKING
from mqt.core import load
from mqt.core.plugins.qiskit import mqt_to_qiskit
from ....sc import (
CommanderGrouping,
Configuration,
EarlyTermination,
Encoding,
Heuristic,
InitialLayout,
Layering,
LookaheadHeuristic,
Method,
SwapReduction,
map_,
)
from .load_architecture import load_architecture
from .load_calibration import load_calibration
if TYPE_CHECKING:
from qiskit.circuit import QuantumCircuit
from qiskit.providers import BackendV2
from qiskit.transpiler.target import Target
from ....sc import Arch, Architecture, MappingResults
from ....types import CircuitInputType
from ....visualization import SearchVisualizer
[docs]
def compile_(
circ: CircuitInputType,
arch: str | Arch | Architecture | BackendV2 | None,
calibration: str | Target | None = None,
method: Method = Method.heuristic,
heuristic: Heuristic = Heuristic.gate_count_max_distance,
initial_layout: InitialLayout = InitialLayout.dynamic,
iterative_bidirectional_routing_passes: int | None = None,
layering: Layering = Layering.individual_gates,
automatic_layer_splits_node_limit: int | None = 5000,
early_termination: EarlyTermination = EarlyTermination.none,
early_termination_limit: int = 0,
lookahead_heuristic: LookaheadHeuristic | None = LookaheadHeuristic.gate_count_max_distance,
lookaheads: int = 15,
lookahead_factor: float = 0.5,
encoding: Encoding = Encoding.commander,
commander_grouping: CommanderGrouping = CommanderGrouping.fixed3,
swap_reduction: SwapReduction = SwapReduction.coupling_limit,
swap_limit: int = 0,
include_wcnf: bool = False,
use_subsets: bool = True,
subgraph: set[int] | None = None,
pre_mapping_optimizations: bool = True,
post_mapping_optimizations: bool = True,
add_measurements_to_mapped_circuit: bool = True,
add_barriers_between_layers: bool = False,
verbose: bool = False,
debug: bool = False,
visualizer: SearchVisualizer | None = None,
) -> tuple[QuantumCircuit, MappingResults]:
"""Interface to the MQT QMAP tool for mapping quantum circuits.
Args:
circ: The circuit to map.
arch: The architecture to map to.
calibration: The calibration to use.
method: The mapping method to use. Defaults to :attr:`~Method.heuristic`.
heuristic: The heuristic function to use for the routing search. Defaults to :attr:`~Heuristic.gate_count_max_distance`.
initial_layout: The initial layout to use. Defaults to :attr:`~InitialLayout.dynamic`.
iterative_bidirectional_routing_passes: Number of iterative bidirectional routing passes to perform or None to disable. Defaults to None.
layering: The layering strategy to use. Defaults to :attr:`~Layering.individual_gates`.
automatic_layer_splits_node_limit: The number of expanded nodes after which to split a layer or None to disable automatic layer splitting. Defaults to 5000.
early_termination: The early termination strategy to use, i.e. terminating the search after a goal node has been found, but before it is guaranteed to be optimal. Defaults to :attr:`~EarlyTermination.none`.
early_termination_limit: The number of nodes (counted according to the early termination strategy) after which to terminate the search early. Defaults to 0.
lookahead_heuristic: The heuristic function to use as a lookahead penalty during search or None to disable lookahead. Defaults to :attr:`~LookaheadHeuristic.gate_count_max_distance`.
lookaheads: The number of lookaheads to be used or None if no lookahead should be used. Defaults to 15.
lookahead_factor: The rate at which the contribution of future layers to the lookahead decreases. Defaults to 0.5.
encoding: The encoding to use for the AMO and exactly one constraints. Defaults to :attr:`~Encoding.naive`.
commander_grouping: The grouping strategy to use for the commander and bimander encoding. Defaults to :attr:`~CommanderGrouping.halves`.
swap_reduction: The swap reduction strategy to use. Defaults to :attr:`~SwapReduction.coupling_limit`.
swap_limit: Set a custom limit for max swaps per layer, for the increasing reduction strategy it sets the max swaps per layer. Defaults to 0.
include_wcnf: Include WCNF file in the results. Defaults to False.
use_subsets: Use qubit subsets, or consider all available physical qubits at once. Defaults to True.
subgraph: List of qubits to consider for mapping (in exact mapper), if None all qubits are considered. Defaults to None.
pre_mapping_optimizations: Run pre-mapping optimizations. Defaults to True.
post_mapping_optimizations: Run post-mapping optimizations. Defaults to True.
add_measurements_to_mapped_circuit: Whether to add measurements at the end of the mapped circuit. Defaults to True.
add_barriers_between_layers: Whether to add barriers between layers to make them apparent after mapping. Defaults to False.
verbose: Print more detailed information during the mapping process. Defaults to False.
debug: Gather additional information during the mapping process (e.g. number of generated nodes, branching factors, ...). Defaults to False.
visualizer: A SearchVisualizer object to log the search process to. Defaults to None.
Returns:
The mapped circuit and the mapping results.
"""
if subgraph is None:
subgraph = set()
if arch is None and calibration is None:
msg = "Either arch or calibration must be specified"
raise ValueError(msg)
architecture = load_architecture(arch)
load_calibration(architecture, calibration)
config = Configuration()
config.method = Method(method)
config.heuristic = Heuristic(heuristic)
config.initial_layout = InitialLayout(initial_layout)
if iterative_bidirectional_routing_passes is None:
config.iterative_bidirectional_routing = False
else:
config.iterative_bidirectional_routing = True
config.iterative_bidirectional_routing_passes = iterative_bidirectional_routing_passes
config.layering = Layering(layering)
if automatic_layer_splits_node_limit is None:
config.automatic_layer_splits = False
else:
config.automatic_layer_splits = True
config.automatic_layer_splits_node_limit = automatic_layer_splits_node_limit
config.early_termination = EarlyTermination(early_termination)
config.early_termination_limit = early_termination_limit
config.encoding = Encoding(encoding)
config.commander_grouping = CommanderGrouping(commander_grouping)
config.swap_reduction = SwapReduction(swap_reduction)
config.swap_limit = swap_limit
config.include_wcnf = include_wcnf
config.use_subsets = use_subsets
config.subgraph = subgraph
config.pre_mapping_optimizations = pre_mapping_optimizations
config.post_mapping_optimizations = post_mapping_optimizations
config.add_measurements_to_mapped_circuit = add_measurements_to_mapped_circuit
config.add_barriers_between_layers = add_barriers_between_layers
config.verbose = verbose
config.debug = debug
if visualizer is not None and visualizer.data_logging_path is not None:
config.data_logging_path = visualizer.data_logging_path
if lookahead_heuristic is None:
config.lookahead_heuristic = LookaheadHeuristic.none
config.lookaheads = 0
else:
config.lookahead_heuristic = LookaheadHeuristic(lookahead_heuristic)
config.lookaheads = lookaheads
config.lookahead_factor = lookahead_factor
qc = load(circ)
qc_mapped, results = map_(qc, architecture, config)
return mqt_to_qiskit(qc_mapped, set_layout=True), results