Skip to main content

cqlib_core/circuit/
mod.rs

1// This code is part of Cqlib.
2//
3// (C) Copyright China Telecom Quantum Group 2025
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//! # Quantum Circuit Module
14//!
15//! Core data structures for representing, constructing, and manipulating quantum
16//! circuits. The [`Circuit`] type is the primary IR container, supporting:
17//!
18//! - **Static circuits**: fixed gate sequences with concrete numeric parameters.
19//! - **Parameterized circuits**: symbolic gate angles for variational algorithms
20//!   (VQE, QAOA, quantum machine learning).
21//! - **Dynamic circuits**: runtime classical control flow driven by mid-circuit
22//!   measurements — conditionals, loops, and switches over typed classical
23//!   expressions.
24//!
25//! ## Module Map
26//!
27//! | Submodule | Purpose | Key types |
28//! |-----------|---------|-----------|
29//! | [`circuit_impl`] | Circuit container and builder API | [`Circuit`] |
30//! | [`bit`] | Qubit identifier and conversions | [`Qubit`], [`QubitError`] |
31//! | [`gate`] | Gate definitions, matrix generation, arity | [`StandardGate`], [`Instruction`], [`UnitaryGate`], [`MCGate`], [`Directive`], [`ClassicalDataOp`] |
32//! | [`operation`] | Storage-IR operation (instruction + qubits + params) | [`Operation`] |
33//! | [`value_instruction`] | Construction-IR operation tree, pre-insertion | [`ValueOperation`], [`ValueInstruction`], [`ValueClassicalControlOp`] |
34//! | [`circuit_param`] | Parameter representation in both IR layers | [`ParameterValue`] (construction), [`CircuitParam`] (storage) |
35//! | [`parameter`] | Symbolic/numeric parameter expressions | [`Parameter`] |
36//! | [`classical`] | Runtime classical storage and type system | [`ClassicalVar`], [`ClassicalValue`], [`ClassicalType`], [`Measurement`] |
37//! | [`classical_expr`] | Side-effect-free typed classical expression AST | [`ClassicalExpr`], [`ClassicalBinaryOp`], [`ClassicalCompareOp`] |
38//! | [`control_flow`] | Structured classical control-flow IR | [`IfOp`], [`WhileOp`], [`ForOp`], [`SwitchOp`], [`ClassicalControlOp`] |
39//! | [`mod@cfg`] | Structured control-flow graph view | [`CircuitCFG`] |
40//! | [`circuit_verify`] | Classical-data and control-flow validation | [`Circuit::validate`] |
41//! | [`mod@circuit_to_matrix`] | Dense unitary matrix computation | [`fn@circuit_to_matrix`] |
42//! | [`ansatz`] | Variational circuit templates | `Ansatz` trait, `TwoLocal`, `QAOAAnsatz` |
43//! | [`symbolic_matrix`] | Dense symbolic unitary for small subcircuits | Symbolic gate and matrix types |
44//! | [`error`] | Unified error type catalog | [`CircuitError`] |
45//!
46//! ## Quick Start
47//!
48//! ### Static circuit: Bell state → unitary matrix
49//!
50//! ```
51//! use cqlib_core::circuit::{Circuit, Qubit};
52//!
53//! let mut c = Circuit::new(2);
54//! c.h(Qubit::new(0)).unwrap();
55//! c.cx(Qubit::new(0), Qubit::new(1)).unwrap();
56//! assert_eq!(c.num_qubits(), 2);
57//! assert_eq!(c.operations().len(), 2);
58//! ```
59//!
60//! ### Parameterized circuit: bind symbolic angles
61//!
62//! ```
63//! use cqlib_core::circuit::{Circuit, Qubit, Parameter};
64//! use std::collections::HashMap;
65//!
66//! let theta = Parameter::symbol("θ");
67//! let mut c = Circuit::new(1);
68//! c.rx(Qubit::new(0), theta.clone()).unwrap();
69//! c.rz(Qubit::new(0), theta).unwrap();
70//!
71//! // Resolve symbols to concrete values
72//! let mut bindings = HashMap::new();
73//! bindings.insert("θ", std::f64::consts::PI);
74//! let evaluated = c.assign_parameters(&Some(bindings)).unwrap();
75//! ```
76//!
77//! ### Dynamic circuit: mid-circuit measurement with conditional gate
78//!
79//! ```
80//! use cqlib_core::circuit::{Circuit, Qubit};
81//!
82//! let mut c = Circuit::new(2);
83//! let q0 = Qubit::new(0);
84//! let q1 = Qubit::new(1);
85//!
86//! c.h(q0).unwrap();
87//! let m = c.measure(q0).unwrap();        // → Bit
88//!
89//! // Apply X on q1 only when q0 measured as |1⟩
90//! c.if_(m.expr().to_bool().unwrap(), |body| {
91//!     body.x(q1)?;
92//!     Ok(())
93//! }).unwrap();
94//! ```
95//!
96//! ## Architecture
97//!
98//! The circuit IR has two layers designed to separate construction ergonomics
99//! from storage efficiency:
100//!
101//! | Layer | Operation type | Parameter type | Purpose |
102//! |-------|---------------|----------------|---------|
103//! | **Construction IR** | [`ValueOperation`] / [`ValueInstruction`] | [`ParameterValue`] | Self-contained, pre-insertion builder |
104//! | **Storage IR** | [`Operation`] / [`Instruction`] | [`CircuitParam`] | Compact, interned, post-insertion storage |
105//!
106//! [`Circuit::from_operations`] and [`Circuit::append_value_operation`] are the
107//! public lowering entry points. They recursively intern symbolic [`Parameter`]
108//! values into the circuit's [`indexmap::IndexSet`] parameter table and replace
109//! them with stable [`CircuitParam::Index`] references. Indexed parameters are
110//! never exposed to construction-IR callers, preventing dangling references.
111//!
112//! ### Validation
113//!
114//! Use [`Circuit::validate`] after construction or after loading external
115//! circuit IR. It checks:
116//!
117//! - Classical handle ownership (no foreign circuit handles)
118//! - Immutable [`ClassicalValue`] dominates all use sites (SSA)
119//! - Scoped values do not escape their defining control-flow regions
120//! - [`break`](ClassicalControlOp::Break) and [`continue`](ClassicalControlOp::Continue)
121//!   appear only in valid terminal positions
122//!
123//! Gate arity and qubit membership are validated eagerly during [`Circuit::append`],
124//! not deferred to post-hoc validation.
125//!
126//! ## Error Handling
127//!
128//! All construction methods that can fail return [`Result<_, CircuitError>`].
129//! Common error variants:
130//!
131//! | Error variant | When |
132//! |--------------|------|
133//! | [`QubitNotFound`] | Qubit not registered in the circuit |
134//! | [`QubitCountMismatch`] / [`ParameterCountMismatch`] | Wrong arity for fixed-arity instruction |
135//! | [`InvalidParameterValue`] | Non-finite (NaN/Inf) fixed parameter |
136//! | [`DuplicateQubits`] | Same qubit used twice in one operation |
137//! | [`ForeignClassicalHandle`] | Handle from another circuit |
138//! | [`UndefinedClassicalValue`] | Read of uninitialized classical value |
139//!
140//! See the [`error`] module for the full catalog with per-variant documentation.
141//!
142//! [`QubitNotFound`]: CircuitError::QubitNotFound
143//! [`QubitCountMismatch`]: CircuitError::QubitCountMismatch
144//! [`ParameterCountMismatch`]: CircuitError::ParameterCountMismatch
145//! [`InvalidParameterValue`]: CircuitError::InvalidParameterValue
146//! [`DuplicateQubits`]: CircuitError::DuplicateQubits
147//! [`ForeignClassicalHandle`]: CircuitError::ForeignClassicalHandle
148//! [`UndefinedClassicalValue`]: CircuitError::UndefinedClassicalValue
149
150pub mod ansatz;
151pub mod bit;
152pub mod cfg;
153mod circuit_classical;
154pub mod circuit_impl;
155pub mod circuit_param;
156pub mod circuit_to_matrix;
157pub mod circuit_verify;
158pub mod classical;
159pub mod classical_expr;
160pub mod control_flow;
161pub mod dag;
162pub mod depth;
163pub mod error;
164pub mod gate;
165pub mod operation;
166pub mod parameter;
167pub mod symbolic_matrix;
168pub mod value_instruction;
169
170#[cfg(test)]
171pub(crate) mod test_utils;
172
173pub use bit::{Qubit, QubitError};
174pub use cfg::CircuitCFG;
175pub use circuit_classical::SwitchBuilder;
176#[doc(hidden)]
177pub use circuit_classical::{ControlBodyTransaction, ExternalControlScope};
178pub use circuit_impl::Circuit;
179pub use circuit_param::{CircuitParam, ParameterValue};
180pub use circuit_to_matrix::circuit_to_matrix;
181#[cfg(any(test, debug_assertions))]
182pub(crate) use circuit_to_matrix::value_operations_to_matrix;
183pub use classical::{CircuitId, ClassicalType, ClassicalValue, ClassicalVar, Measurement};
184pub use classical_expr::{
185    ClassicalBinaryOp, ClassicalCast, ClassicalCompareOp, ClassicalExpr, ClassicalExprKind,
186    ClassicalExprNode, ClassicalUnaryOp,
187};
188pub use control_flow::{
189    ClassicalControlKind, ClassicalControlOp, ControlBody, ForOp, IfOp, SwitchCase, SwitchOp,
190    WhileOp,
191};
192pub use dag::{CircuitDag, DagControlFlow, DagNode, DagSwitchCase, DagWire};
193pub use error::CircuitError;
194pub use gate::circuit_gate::CircuitGate;
195pub use gate::classical_data::ClassicalDataOp;
196pub use gate::directive::Directive;
197pub use gate::instruction::Instruction;
198pub use gate::mc_gate::MCGate;
199pub use gate::standard_gate::StandardGate;
200pub use gate::unitary_gate::UnitaryGate;
201pub use operation::{Operation, ValueOperation};
202pub use parameter::Parameter;
203pub use value_instruction::{
204    ValueClassicalControlOp, ValueControlBody, ValueInstruction, ValueSwitchCase,
205    storage_operation_to_value,
206};