Skip to main content

Circuit

Struct Circuit 

Source
pub struct Circuit { /* private fields */ }
Expand description

A quantum circuit representation serving as the core IR for quantum programs.

The Circuit struct is designed to be a high-performance, memory-efficient container for quantum operations. It supports both static circuits (fixed angles) and parameterized circuits (symbolic angles), making it suitable for a wide range of applications from error correction to variational quantum algorithms.

§Internal Architecture

  • Qubit Storage: Uses IndexSet<Qubit> to maintain deterministic ordering of qubits while allowing $O(1)$ lookups.
  • Parameter Interning: Symbolic parameters are stored in a centralized IndexSet. Instructions reference these parameters by index rather than owning them. This “interning” strategy significantly reduces memory footprint for deep parameterized circuits and enables vectorized parameter updates.

Implementations§

Source§

impl Circuit

Source

pub fn var(&mut self, ty: ClassicalType) -> ClassicalVar

Allocates a mutable runtime classical variable.

Source

pub fn store( &mut self, target: ClassicalVar, value: ClassicalExpr, ) -> Result<(), CircuitError>

Stores a runtime classical expression into a mutable classical variable.

Source

pub fn measure(&mut self, qubit: Qubit) -> Result<Measurement, CircuitError>

Measures one qubit and produces a self-contained measurement handle.

The returned Measurement contains the immutable ClassicalValue for this measurement and the measured qubit. The value may be read by later classical expressions or structured control flow through Measurement::expr. This method does not write mutable classical storage; use Circuit::measure_into when the result must also be stored in a ClassicalVar.

If appending the measurement fails, the allocated classical value is rolled back and the circuit is left unchanged.

Source

pub fn measure_bits<I>( &mut self, qubits: I, ) -> Result<Measurement, CircuitError>
where I: IntoIterator<Item = Qubit>,

Measures qubits and produces a self-contained BitVec measurement handle.

The result width equals the number of qubits. Input order defines bit order: the first qubit maps to bit index 0, the least-significant bit. The returned Measurement keeps that order and contains the immutable ClassicalValue that may be read by later classical expressions or structured control flow.

§Errors

Returns CircuitError::InvalidOperation when qubits is empty. Any error while appending the operation rolls back the allocated classical value and leaves the circuit unchanged.

Source

pub fn measure_into( &mut self, qubit: Qubit, target: ClassicalVar, ) -> Result<Measurement, CircuitError>

Measures one qubit and stores the result into target.

This is a convenience operation equivalent to calling Circuit::measure followed by Circuit::store. It returns the self-contained measurement handle in addition to updating target, so later expressions may read either the original value or the mutable variable.

target must be a ClassicalType::Bit variable owned by this circuit. The measurement and store are appended atomically: if either operation fails, both operations and the allocated measurement value are rolled back.

Source

pub fn measure_bits_into<I>( &mut self, qubits: I, target: ClassicalVar, ) -> Result<Measurement, CircuitError>
where I: IntoIterator<Item = Qubit>,

Measures qubits and stores the resulting BitVec into target.

This is a convenience operation equivalent to calling Circuit::measure_bits followed by Circuit::store. The returned Measurement contains the immutable measurement result; target is the mutable copy written by the generated store operation.

target must be a ClassicalType::BitVec variable owned by this circuit, and its width must equal the number of measured qubits. Input order defines bit order: the first qubit maps to bit index 0, the least-significant bit. The measurement and store are appended atomically and are both rolled back if either operation fails.

Source

pub fn if_<F>( &mut self, condition: ClassicalExpr, then_body: F, ) -> Result<(), CircuitError>
where F: FnOnce(&mut Circuit) -> Result<(), CircuitError>,

Appends a structured if operation controlled by a boolean classical expression.

Source

pub fn if_else<T, E>( &mut self, condition: ClassicalExpr, then_body: T, else_body: E, ) -> Result<(), CircuitError>
where T: FnOnce(&mut Circuit) -> Result<(), CircuitError>, E: FnOnce(&mut Circuit) -> Result<(), CircuitError>,

Appends a structured if/else operation controlled by a boolean classical expression.

Source

pub fn while_<F>( &mut self, condition: ClassicalExpr, body: F, ) -> Result<(), CircuitError>
where F: FnOnce(&mut Circuit) -> Result<(), CircuitError>,

Appends a structured while loop controlled by a boolean classical expression.

Source

pub fn for_uint<F>( &mut self, var: ClassicalVar, start: ClassicalExpr, stop: ClassicalExpr, step: ClassicalExpr, body: F, ) -> Result<(), CircuitError>

Appends an unsigned runtime range loop with half-open [start, stop) semantics.

Source

pub fn switch<F>( &mut self, target: ClassicalExpr, build: F, ) -> Result<(), CircuitError>
where F: FnOnce(&mut SwitchBuilder<'_>) -> Result<(), CircuitError>,

Appends a structured exact-value switch operation over a UInt expression.

Source

pub fn append_control( &mut self, op: ClassicalControlOp, ) -> Result<(), CircuitError>

Appends a raw structured classical-control operation.

Source

pub fn break_loop(&mut self) -> Result<(), CircuitError>

Appends a break to the nearest enclosing loop or switch body.

Source

pub fn continue_loop(&mut self) -> Result<(), CircuitError>

Appends a continue to the nearest enclosing loop body.

Source§

impl Circuit

Source

pub fn new(num_qubits: usize) -> Self

Creates a new, empty quantum circuit with a specified number of qubits.

The qubits will be automatically indexed from 0 to num_qubits - 1.

§Arguments
  • num_qubits - The number of qubits to initialize in the circuit.
§Example
use cqlib_core::circuit::circuit_impl::Circuit;

let circuit = Circuit::new(5);
assert_eq!(circuit.num_qubits(), 5);
Source

pub fn from_qubits(qubits: Vec<Qubit>) -> Result<Circuit, CircuitError>

Creates a circuit from a specific list of qubits.

This is useful when you want to define a sub-circuit or use non-contiguous qubit indices.

§Arguments
  • qubits - A vector of Qubit identifiers.
§Errors

Returns CircuitError::DuplicateQubits if the input vector contains duplicate qubits.

Source

pub fn from_operations( qubits: Vec<Qubit>, operations: impl IntoIterator<Item = ValueOperation>, classical_vars: Option<Vec<ClassicalType>>, classical_values: Option<Vec<ClassicalType>>, ) -> Result<Self, CircuitError>

Creates a circuit from qubits, value-level operations, and optional runtime classical tables.

Operations are appended in order through value-level lowering, so qubit membership is validated and every ParameterValue is interned into this circuit’s parameter table. classical_vars and classical_values are installed before appending operations, allowing expression-based control flow and classical data operations to reference existing circuit-local handles.

§Errors

Returns CircuitError::DuplicateQubits if qubits contains duplicates. Also returns any error from Circuit::append, including CircuitError::QubitNotFound when an operation references a qubit outside the circuit.

Source

pub fn append_value_operation( &mut self, operation: ValueOperation, ) -> Result<(), CircuitError>

Lowers and appends a self-contained value-level operation.

§Errors

Returns errors from value-instruction lowering or Circuit::append.

Source

pub fn add_qubits(&mut self, new_qubits: Vec<Qubit>) -> Result<(), CircuitError>

Adds new qubits to the existing circuit.

§Arguments
  • new_qubits - A vector of new Qubit identifiers to add.
§Errors

Returns CircuitError::DuplicateQubits if any of the new qubits already exist in the circuit or if new_qubits contains duplicates.

Source

pub fn add_parameter(&mut self, param: Parameter) -> (usize, bool)

Interns a parameter and records its symbols.

Returns the stable table index and whether the parameter was newly inserted.

Source

pub fn resolve_parameter( &self, param: &CircuitParam, ) -> Result<Parameter, CircuitError>

Resolves an operation parameter reference into a high-level parameter.

CircuitParam::Fixed values are converted directly into numeric Parameter values after validating that the stored float is finite. CircuitParam::Index values are resolved through this circuit’s parameter table.

§Errors

Returns CircuitError::InvalidParameterValue for non-finite fixed values and CircuitError::InvalidParameterIndex for missing parameter table entries.

Source

pub fn parameter_value( &self, param: &CircuitParam, ) -> Result<ParameterValue, CircuitError>

Resolves an operation parameter reference into an appendable value.

This is useful when rebuilding operations from an existing circuit: fixed values remain fixed, while indexed symbolic parameters are looked up in the circuit parameter table and returned as ParameterValue::Param.

§Errors

Returns CircuitError::InvalidParameterIndex when an indexed parameter does not exist in this circuit’s parameter table.

Source

pub fn map_param( &mut self, param: Parameter, ) -> Result<CircuitParam, CircuitError>

Maps a high-level parameter into the circuit’s operation parameter form.

This is not the same as Circuit::add_parameter. add_parameter always inserts a Parameter into the circuit parameter table and returns the raw table index. map_param first canonicalizes the parameter and then chooses how operations should store it:

  • constant parameters are simplified, evaluated, finite-checked, normalized from -0.0 to 0.0, and returned as CircuitParam::Fixed without being inserted into the parameter table;
  • symbolic parameters are simplified, interned in the parameter table, and returned as CircuitParam::Index. The circuit symbol table is updated when a new symbolic parameter is inserted.
§Errors

Returns CircuitError::InvalidParameter if parameter simplification or constant evaluation fails.

Source

pub fn width(&self) -> usize

Returns the number of qubits in the circuit.

Alias for num_qubits().

Source

pub fn num_qubits(&self) -> usize

Returns the number of qubits in the circuit.

Source

pub fn parameters(&self) -> &IndexSet<Parameter>

Returns the parameters of the circuit.

Source

pub fn symbols(&self) -> &IndexSet<String>

Returns all symbolic variable names present in the parameter registry.

The registry is stable and is not compacted when operations stop using a parameter, so this set may include symbols that are no longer referenced by the executable IR. Use Circuit::used_symbols when only live dependencies are needed.

Source

pub fn used_symbols(&self) -> IndexSet<String>

Returns symbolic variable names referenced by the executable IR.

This includes the global phase and operation parameters in top-level and nested structured control-flow bodies. The result preserves the stable insertion order of Circuit::symbols while filtering out interned but unreferenced symbols.

Source

pub fn uses_symbol(&self, symbol: &str) -> bool

Returns whether symbol is referenced by the circuit’s executable IR.

This inspects the global phase and operation parameters, including parameters in nested structured control-flow bodies. It intentionally does not use the circuit’s symbol registry because that registry may retain symbols that are interned but no longer referenced.

Source

pub fn qubits(&self) -> Vec<Qubit>

Returns a vector of all qubits in the circuit, preserving their insertion order.

Source

pub fn global_phase(&self) -> Parameter

Returns the global phase of the circuit as a Parameter.

Source

pub fn global_phase_param(&self) -> &CircuitParam

Returns the compact storage representation of the global phase.

Source

pub fn set_global_phase(&mut self, phase: Parameter)

Sets the global phase of the circuit.

Source

pub fn operations(&self) -> &[Operation]

Returns storage-IR operations in execution order.

Source

pub fn remove_operation( &mut self, index: usize, ) -> Result<Operation, CircuitError>

Removes a top-level operation from the circuit schedule.

This deletes exactly one operation from the circuit’s top-level operation list. Structured control-flow operations and circuit-backed gates are removed as whole operations; this API does not delete individual operations inside a ControlBody or nested circuit.

If the removed operation defines measurement-backed classical values, those values are removed from the circuit’s immutable classical value table and remaining value references are compacted. Deletion fails atomically when any remaining operation still reads a removed value.

§Errors

Returns the same errors as Self::remove_operations for a single index.

Source

pub fn remove_operations<I>( &mut self, indices: I, ) -> Result<Vec<Operation>, CircuitError>
where I: IntoIterator<Item = usize>,

Removes multiple top-level operations from the circuit schedule.

indices are interpreted against the original top-level operation list before deletion. Duplicate indices are ignored, and removed operations are returned in ascending original-index order. Structured control-flow operations and circuit-backed gates are removed as whole operations; this API does not delete individual operations inside a ControlBody or nested circuit.

If the removed operations define measurement-backed classical values, those values are removed from the circuit’s immutable classical value table and remaining value references are compacted. Deletion fails atomically when any remaining operation still reads a removed value.

§Errors

Returns CircuitError::OperationIndexOutOfBounds when any index is not a valid operation index. Returns CircuitError::ClassicalValueStillInUse when a measurement result defined by the removed operations is still read by an operation that is not also being removed. Also returns any validation or remapping error raised by the candidate circuit after deletion.

Source

pub fn depth(&self, recurse: bool) -> Result<usize, CircuitError>

Returns the circuit depth (longest ASAP schedule path over qubit wires).

Every instruction node contributes one layer on the qubits it touches; barriers synchronize their listed qubits (an empty-qubit barrier is global, synchronizing every circuit qubit). CircuitGate is opaque (depth 1); call decompose first to recurse into nested sub-circuits.

With recurse = false (default), an error is returned if the circuit contains any classical control-flow operation (if/while/for/ switch/break/continue). With recurse = true, control flow is unfolded into an estimated depth: if/switch take the max branch, while counts the body once, for with a statically-known unsigned-literal range is fully unrolled (else counted once).

§Errors

Returns CircuitError::ControlFlowPresent when recurse = false and the circuit contains control flow.

Source

pub fn classical_vars(&self) -> &[ClassicalType]

Returns the static types of runtime classical variables owned by this circuit.

Source

pub fn id(&self) -> CircuitId

Returns this circuit’s process-local identity for constructing explicit classical IR handles.

Source

pub fn classical_values(&self) -> &[ClassicalType]

Returns the static types of immutable runtime classical values owned by this circuit.

Source

pub fn append<Q, P>( &mut self, instruction: Instruction, qubits: Q, params: P, label: Option<&str>, ) -> Result<(), CircuitError>

Appends a generic instruction to the circuit.

This is the low-level method used by all specific gate methods (e.g., h, cx). It handles arity validation, parameter interning, and qubit validation.

§Arguments
  • instruction - The instruction to append (Standard, Extended, or Directive).
  • qubits - The qubits this instruction acts upon.
  • params - The parameters for the instruction (if any).
  • label - An optional label for the operation.
§Errors

Returns CircuitError::QubitCountMismatch or CircuitError::ParameterCountMismatch when a fixed-arity instruction receives the wrong number of operands. Returns CircuitError::DuplicateQubits when the same qubit is supplied more than once and CircuitError::QubitNotFound if a qubit is not present in the circuit. Non-finite fixed parameters produce CircuitError::InvalidParameterValue. Classical data and control-flow instructions may additionally fail their ownership, type, scope, or structural validation.

Source

pub fn h(&mut self, qubit: Qubit) -> Result<(), CircuitError>

Appends a Hadamard (H) gate.

The H gate creates a superposition state: $H|0\rangle = \frac{|0\rangle + |1\rangle}{\sqrt{2}}$.

Source

pub fn i(&mut self, qubit: Qubit) -> Result<(), CircuitError>

Appends an Identity (I) gate.

This is a no-op gate, often used for alignment or waiting.

Source

pub fn x(&mut self, qubit: Qubit) -> Result<(), CircuitError>

Appends a Pauli-X (NOT) gate.

Performs a bit flip: $X|0\rangle = |1\rangle, X|1\rangle = |0\rangle$.

Source

pub fn y(&mut self, qubit: Qubit) -> Result<(), CircuitError>

Appends a Pauli-Y gate.

Performs a bit and phase flip: $Y|0\rangle = i|1\rangle, Y|1\rangle = -i|0\rangle$.

Source

pub fn z(&mut self, qubit: Qubit) -> Result<(), CircuitError>

Appends a Pauli-Z gate.

Performs a phase flip: $Z|0\rangle = |0\rangle, Z|1\rangle = -|1\rangle$.

Source

pub fn x2p(&mut self, qubit: Qubit) -> Result<(), CircuitError>

Appends a $\sqrt{X}$ (SX) gate.

A 90-degree rotation around the X-axis. $SX^2 = X$.

Source

pub fn x2m(&mut self, qubit: Qubit) -> Result<(), CircuitError>

Appends a $\sqrt{X}^\dagger$ (SXdg) gate.

The inverse of the SX gate.

Source

pub fn y2p(&mut self, qubit: Qubit) -> Result<(), CircuitError>

Appends a $\sqrt{Y}$ gate.

Source

pub fn y2m(&mut self, qubit: Qubit) -> Result<(), CircuitError>

Appends a $\sqrt{Y}^\dagger$ gate.

Source

pub fn xy( &mut self, qubit: Qubit, theta: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends an XY gate.

Applies a pi rotation about the axis at angle theta in the single-qubit XY plane.

Source

pub fn xy2p( &mut self, qubit: Qubit, theta: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends a positive half-pi rotation in the single-qubit XY plane.

Source

pub fn xy2m( &mut self, qubit: Qubit, theta: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends a negative half-pi rotation in the single-qubit XY plane.

Source

pub fn s(&mut self, qubit: Qubit) -> Result<(), CircuitError>

Appends an S (Phase) gate.

Applies a phase of $i$ to the $|1\rangle$ state ($Z^{1/2}$).

Source

pub fn sdg(&mut self, qubit: Qubit) -> Result<(), CircuitError>

Appends an S-dagger ($S^\dagger$) gate.

Applies a phase of $-i$ to the $|1\rangle$ state.

Source

pub fn t(&mut self, qubit: Qubit) -> Result<(), CircuitError>

Appends a T gate.

Applies a phase of $e^{i\pi/4}$ to the $|1\rangle$ state ($Z^{1/4}$).

Source

pub fn tdg(&mut self, qubit: Qubit) -> Result<(), CircuitError>

Appends a T-dagger ($T^\dagger$) gate.

Source

pub fn rx( &mut self, qubit: Qubit, theta: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends a rotation around the X-axis by angle theta.

$RX(\theta) = e^{-i\theta X/2}$

Source

pub fn ry( &mut self, qubit: Qubit, theta: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends a rotation around the Y-axis by angle theta.

$RY(\theta) = e^{-i\theta Y/2}$

Source

pub fn rz( &mut self, qubit: Qubit, theta: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends a rotation around the Z-axis by angle theta.

$RZ(\theta) = e^{-i\theta Z/2}$

Source

pub fn phase( &mut self, qubit: Qubit, lambda: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends a Phase gate (P gate).

Applies a phase of $e^{i\lambda}$ to the $|1\rangle$ state. Equivalent to $RZ(\lambda)$ up to a global phase.

Source

pub fn u( &mut self, qubit: Qubit, theta: impl Into<ParameterValue>, phi: impl Into<ParameterValue>, lambda: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends a generic single-qubit rotation gate $U(\theta, \phi, \lambda)$.

This is the most general single-qubit unitary gate. $$ U(\theta, \phi, \lambda) = \begin{pmatrix} \cos(\theta/2) & -e^{i\lambda}\sin(\theta/2) \ e^{i\phi}\sin(\theta/2) & e^{i(\phi+\lambda)}\cos(\theta/2) \end{pmatrix} $$

Source

pub fn cx(&mut self, control: Qubit, target: Qubit) -> Result<(), CircuitError>

Appends a Controlled-NOT (CX or CNOT) gate.

Flips the target qubit if and only if the control qubit is $|1\rangle$.

Source

pub fn cy(&mut self, control: Qubit, target: Qubit) -> Result<(), CircuitError>

Appends a Controlled-Y (CY) gate.

Source

pub fn cz(&mut self, control: Qubit, target: Qubit) -> Result<(), CircuitError>

Appends a Controlled-Z (CZ) gate.

Adds a phase of -1 only if both qubits are $|1\rangle$.

Source

pub fn swap(&mut self, a: Qubit, b: Qubit) -> Result<(), CircuitError>

Appends a SWAP gate.

Exchange the states of two qubits.

Source

pub fn rxx( &mut self, a: Qubit, b: Qubit, theta: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends an Ising XX coupling gate ($R_{XX}(\theta)$).

$R_{XX}(\theta) = e^{-i\theta X \otimes X / 2}$

Source

pub fn ryy( &mut self, a: Qubit, b: Qubit, theta: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends an Ising YY coupling gate ($R_{YY}(\theta)$).

$R_{YY}(\theta) = e^{-i\theta Y \otimes Y / 2}$

Source

pub fn rzz( &mut self, a: Qubit, b: Qubit, theta: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends an Ising ZZ coupling gate ($R_{ZZ}(\theta)$).

$R_{ZZ}(\theta) = e^{-i\theta Z \otimes Z / 2}$

Source

pub fn rzx( &mut self, a: Qubit, b: Qubit, theta: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends an Ising ZX coupling gate ($R_{ZX}(\theta)$).

$R_{ZX}(\theta) = e^{-i\theta Z \otimes X / 2}$

Source

pub fn crx( &mut self, control: Qubit, target: Qubit, theta: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends a Controlled-RX gate (CRX).

Performs an X-rotation on the target if the control is $|1\rangle$.

Source

pub fn cry( &mut self, control: Qubit, target: Qubit, theta: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends a Controlled-RY gate (CRY).

Source

pub fn crz( &mut self, control: Qubit, target: Qubit, theta: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends a Controlled-RZ gate (CRZ).

Source

pub fn ccx( &mut self, control1: Qubit, control2: Qubit, target: Qubit, ) -> Result<(), CircuitError>

Appends a Toffoli gate (CCX).

A 3-qubit gate where the target flips if and only if both controls are $|1\rangle$.

Source

pub fn fsim( &mut self, a: Qubit, b: Qubit, theta: impl Into<ParameterValue>, phi: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends a Fermionic Simulation gate (fSim).

Useful in quantum chemistry simulations.

$$ \text{fSim}(\theta, \phi) = \begin{pmatrix} 1 & 0 & 0 & 0 \ 0 & \cos\theta & -i\sin\theta & 0 \ 0 & -i\sin\theta & \cos\theta & 0 \ 0 & 0 & 0 & e^{-i\phi} \end{pmatrix} $$

Source

pub fn rxy( &mut self, qubit: Qubit, theta: impl Into<ParameterValue>, phi: impl Into<ParameterValue>, ) -> Result<(), CircuitError>

Appends a rotation in the XY plane.

Source

pub fn barrier(&mut self, qubits: Vec<Qubit>) -> Result<(), CircuitError>

Inserts a Barrier.

A barrier forbids the compiler from optimizing or reordering across this line. It has no physical effect on the quantum state, but is crucial for debugging and manual optimization control.

A non-empty qubits list creates a barrier over exactly those qubits. An empty list creates a global barrier over every qubit in this circuit.

Source

pub fn reset(&mut self, qubit: Qubit) -> Result<(), CircuitError>

Resets a qubit to the $|0\rangle$ state.

This is a non-unitary operation.

Source

pub fn multi_control<I, C, T, P>( &mut self, instruction: I, controls: C, targets: T, params: P, ) -> Result<(), CircuitError>

Applies a multi-controlled version of a standard gate.

This method automatically handles gate promotion. For example, applying X with 1 control becomes CX, and with 2 controls becomes CCX. For higher numbers of controls, it creates an Instruction::McGate.

§Arguments
  • gate - The base standard gate to apply (e.g., X, Y, RX).
  • controls - A list of control qubits.
  • targets - A list of target qubits.
  • params - Parameters for the base gate.
§Example
use cqlib_core::circuit::circuit_impl::Circuit;
use cqlib_core::circuit::Qubit;
use cqlib_core::circuit::gate::StandardGate;

let mut circuit = Circuit::new(4);
let q0 = Qubit::new(0);
let q1 = Qubit::new(1);
let q2 = Qubit::new(2);

// Equivalent to CCX(q0, q1, q2)
circuit.multi_control(StandardGate::X, [q0, q1], vec![q2], []).unwrap();
Source

pub fn unitary( &mut self, gate: UnitaryGate, qubits: Vec<Qubit>, ) -> Result<(), CircuitError>

Appends a custom unitary gate to the circuit.

This allows inserting user-defined gates defined by a specific matrix.

§Arguments
  • definition - The definition of the custom gate (matrix, label, etc.).
  • qubits - The list of qubits to apply the gate to.
§Example
use ndarray::Array2;
use num_complex::Complex64;
use cqlib_core::circuit::circuit_impl::Circuit;
use cqlib_core::circuit::gate::UnitaryGate;
use cqlib_core::circuit::Qubit;

// Define a custom gate (e.g., Identity)
let mat = Array2::eye(2).mapv(|x| Complex64::new(x, 0.0));
let u_gate = UnitaryGate::new("MyGate", 1, 0)
     .with_matrix(mat)
     .unwrap();

let mut circuit = Circuit::new(4);
let q0 = Qubit::new(0);

// Apply the custom gate
circuit.unitary(u_gate, vec![q0]).unwrap();
Source

pub fn unitary_with_params<P>( &mut self, gate: UnitaryGate, qubits: Vec<Qubit>, params: P, ) -> Result<(), CircuitError>
where P: IntoIterator<Item = ParameterValue>,

Appends a parameterized custom unitary gate to the circuit.

Source

pub fn delay( &mut self, qubit: impl Into<Qubit>, delay: ParameterValue, ) -> Result<(), CircuitError>

Appends a Delay instruction to the circuit.

This instruction represents an idle period on a specific qubit, often used for dynamical decoupling or timing control in pulse-level scheduling.

§Arguments
  • qubit - The qubit to apply the delay to.
  • delay - The duration of the delay. The unit depends on the target backend (e.g., seconds, samples, or dt).
Source

pub fn circuit_gate( &mut self, gate: CircuitGate, qubits: Vec<Qubit>, params: impl IntoIterator<Item = ParameterValue>, ) -> Result<(), CircuitError>

Appends a pre-compiled CircuitGate to this circuit.

This allows nesting circuits within circuits.

§Arguments
  • gate - The CircuitGate instance to append.
  • qubits - The qubits in this circuit that the sub-circuit acts upon.
  • params - The parameter values to bind to the sub-circuit’s parameters.
Source

pub fn inverse(&self) -> Result<Circuit, CircuitError>

Creates the inverse (adjoint) of the circuit.

The inverse circuit represents the unitary $U^\dagger$ such that $U^\dagger U = I$.

§Errors

Returns CircuitError::IrreversibleOperation if the circuit contains non-unitary operations (e.g., Measure, Reset) or gates that cannot be symbolically inverted.

Source

pub fn to_gate( self, name: impl Into<String>, ) -> Result<Instruction, CircuitError>

Converts the circuit into a CircuitGate instruction.

This method “freezes” the current circuit and wraps it into an instruction that can be appended to another circuit. Its positional parameter signature is inferred from symbols currently referenced by the executable IR, in stable registry order.

§Arguments
  • name - A name for the new gate.
Source

pub fn decompose(&self) -> Result<Circuit, CircuitError>

Decomposes the circuit by resolving sub-circuit gates into their fundamental operations.

This method recursively unpacks any Instruction::CircuitGate (hierarchical instructions) found in the circuit. It handles:

  1. Parameter Substitution: Parameters in the sub-circuit are replaced by the arguments passed from the parent circuit.
    • Example: If sub-circuit has Rx(theta+1) and is called with theta = beta, the result is Rx(beta+1).
  2. Qubit Mapping: Virtual qubits in the sub-circuit definition are mapped to the physical qubits in the parent circuit.
  3. Global Phase: Each sub-circuit’s phase is substituted using its call arguments and accumulated into the flattened circuit, including empty definitions.
§Returns
  • Ok(Circuit): A new flattened Circuit containing only base instructions (Standard, Unitary, Directives).
  • Err(CircuitError): If a parameter cannot be resolved during decomposition.
§Errors

Returns an error if a fully resolved parameter or accumulated global phase is invalid, or if the circuit contains unsupported classical control. Unbound symbolic parameters and phases are preserved.

Source

pub fn to_matrix( &self, qubits_order: Option<&[usize]>, ) -> Result<Array2<Complex64>, CircuitError>

Computes the dense unitary matrix represented by this circuit.

The first qubit in qubits_order is mapped to the least-significant basis-state bit. When no order is supplied, qubits are sorted by their numeric identifiers. The returned matrix includes the circuit’s global phase.

The matrix dimension is 2^n and its element count is 4^n for n qubits. This API is therefore intended only for small circuits.

§Errors

Returns an error when the circuit contains a non-unitary operation, unresolved symbolic parameter, invalid qubit order, unsupported gate definition, or a matrix dimension that cannot be represented.

Source

pub fn assign_parameters( &self, bindings: &Option<HashMap<&str, f64>>, ) -> Result<Circuit, CircuitError>

Returns a new circuit with the supplied symbols replaced by numeric values.

Parameters that remain symbolic are simplified and re-interned in the returned circuit. The original circuit is not modified. Internal classical references are remapped to the returned circuit’s identity; handles from the original circuit remain owned by it.

§Errors

Returns an error for unsupported classical control flow, failed symbolic simplification, or an invalid stored parameter index.

Source

pub fn compose( &mut self, other: &Circuit, qubits_map: Option<&[Qubit]>, ) -> Result<(), CircuitError>

Composes another circuit into this circuit.

This method merges the operations from other circuit into self. Qubits from other can either be mapped to existing qubits in self (via qubits_map) or merged by their Qubit IDs. Circuit-local classical variables and values from other are appended to self’s classical tables, and all classical data/control references inside copied operations are remapped to those new local IDs. The identity of self and its existing classical handles are preserved. If composition returns an error, self is unchanged.

§Arguments
  • other - The circuit to compose into this circuit.
  • qubits_map - An optional slice mapping qubits from other to qubits in self.
    • If Some(mapping) is provided, each qubit in other (in insertion order) is mapped to the corresponding qubit in mapping. Target qubits must be distinct, including targets corresponding to idle source qubits.
    • If None is provided, qubits are mapped by ID. IDs not already present in self are appended, while matching IDs reuse the existing qubits.
§Returns
  • Ok(()) - If composition succeeds.
  • Err(CircuitError) - If the mapping has the wrong length, contains duplicate targets (CircuitError::DuplicateQubits), references non-existent qubits, or stored circuit references cannot be remapped.
§Examples
use cqlib_core::circuit::circuit_impl::Circuit;
use cqlib_core::circuit::Qubit;

// Create qc1 with qubits 1, 3, 5
let mut qc1 = Circuit::new(0);
let q1 = Qubit::new(1);
let q3 = Qubit::new(3);
let q5 = Qubit::new(5);
qc1.add_qubits(vec![q1, q3, q5]).unwrap();
qc1.h(q1).unwrap();

// Create qc2 with qubits 1, 2
let mut qc2 = Circuit::new(0);
let q2 = Qubit::new(2);
qc2.add_qubits(vec![q1, q2]).unwrap();
qc2.x(q1).unwrap();

// Compose qc2 into qc1, mapping qc2's qubits: q1->q3, q2->q1
qc1.compose(&qc2, Some(&[q3, q1])).unwrap();
Source

pub fn index(&self, i: usize) -> Result<ValueOperation, CircuitError>

Returns an operation with its parameters resolved to value-level representations.

Unlike Circuit::operations, which exposes the compact storage IR, this method converts indexed parameters back into ParameterValues.

§Errors

Returns CircuitError::OperationIndexOutOfBounds when i is not a valid operation index. Returns CircuitError::InvalidParameterIndex if the stored operation references a missing entry in this circuit’s parameter table.

§Examples
use cqlib_core::circuit::{Circuit, CircuitError};

let circuit = Circuit::new(1);
assert!(matches!(
    circuit.index(0),
    Err(CircuitError::OperationIndexOutOfBounds { index: 0, len: 0 })
));
Source§

impl Circuit

Source

pub fn validate(&self) -> Result<(), CircuitError>

Validates classical handle ownership, measurement definitions, SSA use availability, and structured control-flow value scope.

Validation does not mutate the circuit and may be called after loading, transforming, or manually constructing circuit IR.

§Errors

Returns a CircuitError describing the first ownership, definition, type, scope, or control-flow placement violation encountered.

Trait Implementations§

Source§

impl Clone for Circuit

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Circuit

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<usize> for Circuit

Source§

fn from(num_qubits: usize) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for Circuit

Compares exact compiler-IR structure while ignoring process-local circuit identity.

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl PauliEvolution for Circuit

Source§

fn pauli_evolution( &mut self, pauli: &PauliString, angle: impl Into<ParameterValue>, qubits: &[Qubit], ) -> Result<(), CircuitError>

Appends a Pauli evolution gate $e^{-i\theta/2 \cdot P}$ to the circuit. Read more
Source§

impl TryFrom<&Circuit> for CircuitCFG

Source§

type Error = CircuitError

The type returned in the event of a conversion error.
Source§

fn try_from(circuit: &Circuit) -> Result<Self, Self::Error>

Performs the conversion.
Source§

impl TryFrom<&Circuit> for CircuitDag

Source§

type Error = CircuitError

The type returned in the event of a conversion error.
Source§

fn try_from(circuit: &Circuit) -> Result<Self, Self::Error>

Performs the conversion.
Source§

impl TryFrom<&CircuitCFG> for Circuit

Source§

type Error = CircuitError

The type returned in the event of a conversion error.
Source§

fn try_from(cfg: &CircuitCFG) -> Result<Self, Self::Error>

Performs the conversion.
Source§

impl TryFrom<&CircuitDag> for Circuit

Source§

type Error = CircuitError

The type returned in the event of a conversion error.
Source§

fn try_from(dag: &CircuitDag) -> Result<Self, Self::Error>

Performs the conversion.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> ByRef<T> for T

Source§

fn by_ref(&self) -> &T

Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> DistributionExt for T
where T: ?Sized,

Source§

fn rand<T>(&self, rng: &mut (impl Rng + ?Sized)) -> T
where Self: Distribution<T>,

Source§

impl<T> FmtForward for T

Source§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
Source§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
Source§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
Source§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
Source§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
Source§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
Source§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
Source§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
Source§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Imply<T> for U
where T: ?Sized, U: ?Sized,

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pipe for T
where T: ?Sized,

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
Source§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
Source§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V