cqlib_core/compile/transform/layout/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//! Initial-layout algorithms for quantum compilation.
14//!
15//! A layout maps each logical circuit qubit to one usable physical qubit on a
16//! target device. This module only chooses that initial mapping. It does not
17//! insert SWAP operations, rewrite instructions, or produce a fully routed
18//! physical circuit; routing is handled by later compiler stages such as the
19//! SABRE routing core.
20//!
21//! The shared pipeline is:
22//!
23//! 1. [`analyze_circuit_for_layout`] extracts weighted logical interactions
24//! from a [`Circuit`](crate::circuit::Circuit).
25//! 2. [`PhysicalLayoutGraph::from_device`] turns a [`Device`](crate::device::Device)
26//! into a compiler-local physical topology and calibration view.
27//! 3. A concrete algorithm, such as [`trivial_layout`], [`greedy_layout`],
28//! [`vf2_perfect_layout`], or [`sabre_layout`], returns a [`LayoutResult`].
29//!
30//! Mixed quantum/classical circuits are analyzed structurally. Layout analysis
31//! recursively visits `if`, `while`, `for`, and `switch` bodies so interactions
32//! hidden behind classical control still influence the initial mapping. It does
33//! not estimate branch probabilities, loop trip counts, or runtime paths.
34//!
35//! # Examples
36//!
37//! ```rust
38//! use cqlib_core::circuit::{Circuit, Qubit};
39//! use cqlib_core::compile::transform::{LayoutObjective, trivial_layout};
40//! use cqlib_core::device::Device;
41//!
42//! let mut circuit = Circuit::new(2);
43//! circuit.cx(Qubit::new(0), Qubit::new(1)).unwrap();
44//! let device = Device::line("line-2", 2).unwrap();
45//!
46//! let result = trivial_layout(&circuit, &device, &LayoutObjective::topology_only()).unwrap();
47//! assert!(result.score.is_some());
48//! ```
49
50mod analysis;
51mod greedy;
52mod interaction_seed;
53mod objective;
54mod result;
55mod sabre;
56mod scoring;
57mod trivial;
58mod vf2;
59mod vf2_engine;
60
61pub use crate::compile::physical_target::{DistanceTable, PhysicalLayoutGraph};
62pub use analysis::{
63 CircuitLayoutAnalysis, Interaction, InteractionGraph, analyze_circuit_for_layout,
64};
65pub(crate) use greedy::{GreedyCandidateOutcome, greedy_layout_candidate_prepared};
66pub use greedy::{greedy_layout, greedy_layout_prepared};
67pub use objective::{LayoutObjective, LayoutScore};
68pub use result::{LayoutDiagnostics, LayoutResult};
69pub use sabre::{
70 PreparedSabreCircuit, PreparedSabreTarget, prepare_sabre_circuit, prepare_sabre_device_target,
71 prepare_sabre_topology_target, sabre_layout, sabre_layout_prepared,
72};
73pub(crate) use sabre::{
74 PreparedSabreParetoSearch, SabreParetoCandidateId,
75 prepare_sabre_device_target_with_session_and_physical,
76 prepare_sabre_topology_target_with_prepared, sabre_route_selection_prepared,
77};
78pub use trivial::{trivial_layout, trivial_layout_prepared};
79pub use vf2::{
80 Vf2EdgeRequirement, Vf2LayoutConfig, vf2_perfect_layout, vf2_perfect_layout_prepared,
81};
82pub(crate) use vf2::{Vf2PreparedOutcome, try_vf2_perfect_layout_prepared};
83
84/// Returns whether a layout realizes all positive-weight interactions directly.
85///
86/// This shared helper is intentionally topology-only. Direction mismatch and
87/// calibration quality are represented by [`LayoutObjective`] rather than by
88/// the perfect-layout diagnostic.
89fn is_perfect_layout(
90 analysis: &CircuitLayoutAnalysis,
91 physical: &PhysicalLayoutGraph,
92 layout: &crate::device::Layout,
93) -> bool {
94 // "Perfect" is a topology property: every positive-weight logical
95 // interaction is already adjacent on the device. Coupling direction and
96 // calibration quality are intentionally scored elsewhere.
97 analysis
98 .interactions
99 .interactions()
100 .iter()
101 .filter(|interaction| interaction.weight > 0.0)
102 .all(|interaction| {
103 let Some(left) = layout.get_physical(interaction.left) else {
104 return false;
105 };
106 let Some(right) = layout.get_physical(interaction.right) else {
107 return false;
108 };
109 physical.is_adjacent_undirected(left, right)
110 })
111}
112
113#[cfg(test)]
114mod greedy_test;
115
116#[cfg(test)]
117mod gate_aware_test;
118
119#[cfg(test)]
120mod layout_test;
121
122#[cfg(test)]
123mod sabre_test;
124
125#[cfg(test)]
126mod vf2_test;