cqlib_core/compile/compiler.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.
6// You may obtain a copy of this license in the LICENSE.txt file in
7// the root directory of this source tree or at
8// http://www.apache.org/licenses/LICENSE-2.0.
9//
10// Any modifications or derivative works of this code must retain this
11// copyright notice, and modified files need to carry a notice indicating
12// that they have been altered from the originals.
13
14//! Public compiler entry point.
15//!
16//! The compiler entry point runs the configured [`CompilerWorkflow`]
17//! and returns the optimized circuit plus step-level diagnostics. The workflow
18//! starts from a logical circuit, applies canonicalization, definition
19//! expansion, knowledge-based rewrite, unitary and multi-controlled-gate
20//! decomposition, optional device layout/routing, and target lowering.
21//!
22//! [`CompileTarget`] makes the target contract explicit: compilation is either
23//! logical, lowered to a requested basis, or routed and legalized for one
24//! concrete device. Device compilation uses the device topology for capacity
25//! checks and SABRE routing, then checks every emitted standard operation
26//! against the device's ordered native capabilities before final validation.
27//!
28//! [`CompileMode::Normal`] selects conservative production defaults.
29//! [`CompileMode::Enhanced`] keeps the same semantic contract but spends more
30//! rewrite, resynthesis, native-optimization, and routing effort, runs additional
31//! cleanup around routing and target lowering, and, for a strict device target,
32//! selects among fully lowered and validated routes with a bounded SABRE Pareto
33//! beam.
34
35use super::workflow::CompilerWorkflow;
36use crate::circuit::{Circuit, Instruction};
37use crate::compile::resource::ResourcePolicy;
38use crate::compile::transform::VirtualPermutation;
39use crate::compile::{CompilerError, WorkflowStepReport};
40use crate::device::{Device, Layout};
41
42/// Optimization effort selected for the compiler workflow.
43#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
44pub enum CompileMode {
45 /// Conservative logical optimization using production pass defaults.
46 #[default]
47 Normal,
48 /// A richer staged workflow with stronger pass budgets, target-aware
49 /// cleanup, and validated SABRE Pareto route selection for strict device
50 /// targets.
51 Enhanced,
52}
53
54/// User-facing configuration for [`compile`].
55///
56/// The configuration describes logical optimization effort, optional target
57/// constraints, and the ancillary-resource permissions available before layout.
58#[derive(Debug, Clone)]
59pub struct CompileConfig {
60 /// Optimization workflow mode.
61 pub mode: CompileMode,
62 /// Mutually exclusive logical, basis, or physical-device target.
63 pub target: CompileTarget,
64 /// Ancillary-resource permission for pre-layout decomposition passes.
65 ///
66 /// This controls whether logical clean ancillas may be allocated or dirty
67 /// input qubits may be borrowed. A device target derives hard capacity
68 /// from its usable physical qubits rather than this policy.
69 pub resource_policy: ResourcePolicy,
70}
71
72/// Target contract selected for a compilation run.
73///
74/// Device targets intentionally stay inline so the public configuration API
75/// does not require allocation solely to select a target. Compile
76/// configurations are coarse workflow objects, not per-operation data.
77#[allow(clippy::large_enum_variant)]
78#[derive(Debug, Clone)]
79pub enum CompileTarget {
80 /// Compile in logical qubit space without target-specific lowering.
81 Logical,
82 /// Lower to an explicit standard-gate basis.
83 Basis(Vec<Instruction>),
84 /// Route and lower for one concrete target device.
85 Device(DeviceCompileTarget),
86 /// Route on a device topology while lowering to an explicit gate basis.
87 ///
88 /// This target uses the device for capacity, layout, and
89 /// routing only. It does not require the output basis to match the
90 /// device's native capabilities and therefore does not perform exact
91 /// device-native lowering or final device validation.
92 TopologyBasis {
93 /// Device-specific layout and routing inputs.
94 device_target: DeviceCompileTarget,
95 /// Explicit standard-gate basis required at the output.
96 basis: Vec<Instruction>,
97 },
98}
99
100/// Device-specific compilation inputs.
101#[derive(Debug, Clone)]
102pub struct DeviceCompileTarget {
103 /// Device whose ordered native capabilities constrain the output.
104 pub device: Device,
105 /// Optional caller-supplied initial logical-to-physical layout.
106 pub initial_layout: Option<Layout>,
107 /// Optional deterministic seed for device layout and routing heuristics.
108 pub seed: Option<u32>,
109}
110
111/// Physical-layout information produced by device compilation.
112#[derive(Debug, Clone, PartialEq)]
113pub struct DeviceCompilationMetadata {
114 /// Logical-to-physical layout before routing begins.
115 pub initial_layout: Layout,
116 /// Original logical-output-to-physical layout after all routed swaps and
117 /// pre-layout virtual permutations.
118 pub final_layout: Layout,
119 /// Original logical output to rewritten logical output mapping accumulated
120 /// before physical layout. The initial circuit inputs remain identity-mapped.
121 pub virtual_permutation: VirtualPermutation,
122}
123
124/// Result returned by [`compile`].
125#[derive(Debug, Clone, PartialEq)]
126pub struct CompileResult {
127 /// Optimized circuit.
128 pub circuit: Circuit,
129 /// Whether any workflow step changed the input representation.
130 pub changed: bool,
131 /// Workflow mode used for this run.
132 pub mode: CompileMode,
133 /// Step-level report for the retained output path, in workflow order.
134 ///
135 /// Enhanced strict-device compilation may evaluate other route branches.
136 /// Discarded branches are summarized by `select.sabre_pareto_beam` rather
137 /// than retained as complete step sequences here.
138 pub steps: Vec<WorkflowStepReport>,
139 /// Physical-layout data when compilation used device-topology routing.
140 pub device_metadata: Option<DeviceCompilationMetadata>,
141}
142
143impl CompileResult {
144 /// Returns the first workflow report with the requested step name.
145 pub fn step(&self, name: &str) -> Option<&WorkflowStepReport> {
146 self.steps.iter().find(|step| step.name == name)
147 }
148
149 /// Returns whether any report with the requested name changed the circuit.
150 ///
151 /// Skipped reports are not considered changes.
152 pub fn step_changed(&self, name: &str) -> bool {
153 self.steps
154 .iter()
155 .any(|step| step.name == name && step.changed && !step.skipped)
156 }
157}
158
159/// Runs the configured compiler workflow over `circuit`.
160///
161/// The returned result records the optimized circuit and step-level reports for
162/// the retained output path in workflow order. A device target additionally
163/// returns its initial and final layouts. Errors are reported when a configured
164/// target, native realization, or candidate validation cannot be satisfied.
165///
166/// # Examples
167///
168/// ```rust
169/// use cqlib_core::circuit::{Circuit, Qubit};
170/// use cqlib_core::compile::{CompileConfig, CompileMode, CompileTarget, compile};
171/// use cqlib_core::compile::resource::ResourcePolicy;
172///
173/// let mut circuit = Circuit::new(2);
174/// circuit.h(Qubit::new(0)).unwrap();
175/// circuit.cx(Qubit::new(0), Qubit::new(1)).unwrap();
176///
177/// let result = compile(
178/// &circuit,
179/// CompileConfig {
180/// mode: CompileMode::Normal,
181/// target: CompileTarget::Logical,
182/// resource_policy: ResourcePolicy::default(),
183/// },
184/// )
185/// .unwrap();
186///
187/// assert_eq!(result.mode, CompileMode::Normal);
188/// assert!(!result.steps.is_empty());
189/// assert_eq!(result.circuit.qubits().len(), 2);
190/// ```
191pub fn compile(circuit: &Circuit, config: CompileConfig) -> Result<CompileResult, CompilerError> {
192 CompilerWorkflow::try_new(config)?.run(circuit)
193}
194
195/// Runs the configured compiler workflow by consuming `circuit`.
196///
197/// This is equivalent to [`compile`] but avoids cloning the complete input
198/// circuit when the caller no longer needs it.
199pub fn compile_owned(
200 circuit: Circuit,
201 config: CompileConfig,
202) -> Result<CompileResult, CompilerError> {
203 CompilerWorkflow::try_new(config)?.run_owned(circuit)
204}
205
206#[cfg(test)]
207#[path = "./compile_test.rs"]
208mod compile_test;