cqlib_core/compile/transform/routing/mod.rs
1// This code is part of Cqlib.
2//
3// (C) Copyright China Telecom Quantum Group 2025-2026
4//
5// This code is licensed under the Apache License, Version 2.0. You may
6// obtain a copy of this license in the LICENSE.txt file in the root directory
7// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8//
9// Any modifications or derivative works of this code must retain this
10// copyright notice, and modified files need to carry a notice indicating
11// that they have been altered from the originals.
12
13//! Device-aware routing transforms.
14//!
15//! Routing transforms rebuild a logical [`Circuit`](crate::circuit::Circuit)
16//! into a physical circuit that satisfies a target
17//! [`Device`](crate::device::Device) topology. A routing algorithm selects or
18//! consumes a logical-to-physical layout and inserts SWAP operations when
19//! needed.
20//!
21//! This module is an algorithm boundary, not a compiler workflow. It does not
22//! choose when routing should run, lower operations to a target basis, or mutate
23//! device topology facts. Concrete algorithms live in submodules such as
24//! [`sabre`].
25//!
26//! # Entry Points
27//!
28//! - [`route_sabre`] selects an initial layout with SABRE layout refinement,
29//! then routes the circuit from that layout.
30//! - [`route_with_layout`] routes from a caller-supplied initial layout and
31//! skips automatic layout selection.
32//!
33//! The public compiler workflow uses [`route_with_layout`] when
34//! [`DeviceCompileTarget::initial_layout`](crate::compile::DeviceCompileTarget::initial_layout)
35//! is set, otherwise it uses [`route_sabre`]. Routed circuits use physical
36//! qubit identifiers and guarantee undirected physical adjacency for routed
37//! two-qubit operations. Target-basis translation and exact directed device
38//! lowering remain separate compiler stages.
39//!
40//! # Example
41//!
42//! ```
43//! use cqlib_core::circuit::{Circuit, Qubit};
44//! use cqlib_core::compile::sabre::SabreConfig;
45//! use cqlib_core::compile::transform::LayoutObjective;
46//! use cqlib_core::compile::transform::routing::route_sabre;
47//! use cqlib_core::device::{Device, PhysicalQubit, Topology};
48//! use std::collections::HashSet;
49//!
50//! let physical = vec![
51//! PhysicalQubit::new(0),
52//! PhysicalQubit::new(1),
53//! PhysicalQubit::new(2),
54//! ];
55//! let topology = Topology::new(
56//! physical.clone(),
57//! vec![
58//! (PhysicalQubit::new(0), PhysicalQubit::new(1), "cx".to_string()),
59//! (PhysicalQubit::new(1), PhysicalQubit::new(2), "cx".to_string()),
60//! ],
61//! )?;
62//! let device = Device::new(
63//! "line3",
64//! physical.iter().copied().collect::<HashSet<_>>(),
65//! topology,
66//! )?;
67//!
68//! let mut circuit = Circuit::new(3);
69//! circuit.cx(Qubit::new(0), Qubit::new(2))?;
70//!
71//! let routed = route_sabre(
72//! &circuit,
73//! &device,
74//! &LayoutObjective::topology_only(),
75//! &SabreConfig::default(),
76//! )?;
77//!
78//! assert_all_two_qubit_ops_are_local(routed.circuit());
79//! # fn assert_all_two_qubit_ops_are_local(_: &Circuit) {}
80//! # Ok::<(), Box<dyn std::error::Error>>(())
81//! ```
82
83pub mod sabre;
84
85pub use sabre::{RoutedCircuit, SabreRouteResult, route_sabre, route_with_layout};
86pub(crate) use sabre::{
87 SabreParetoRouteCandidate, prepare_sabre_pareto_routes_with_session_on_physical,
88 route_sabre_tracked_on_topology, route_sabre_tracked_with_session_on_physical,
89 route_with_layout_tracked_on_topology, route_with_layout_tracked_with_session_on_physical,
90};