Skip to main content

cqlib_core/qis/
error.rs

1// This code is part of Cqlib.
2//
3// (C) Copyright China Telecom Quantum Group 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
13use crate::circuit::CircuitError;
14use num_complex::Complex64;
15use thiserror::Error;
16
17/// Comprehensive error type for the `qis` (Quantum Information Science) module.
18///
19/// This enum captures errors that can occur during statevector simulation,
20/// density matrix simulation, observables, Hamiltonians, and Pauli operator manipulations.
21#[derive(Debug, Error)]
22pub enum QisError {
23    /// A fermionic mode lies outside the declared mode space.
24    #[error("Fermionic mode {mode} is out of bounds for {num_modes} modes")]
25    ModeOutOfBounds { mode: usize, num_modes: usize },
26
27    /// Fermionic operators must declare the same mode count.
28    #[error("Mode count mismatch: expected {expected}, got {actual}")]
29    ModeMismatch { expected: usize, actual: usize },
30
31    /// Operator coefficients and arithmetic results must be finite.
32    #[error("Operator coefficient must be finite, got {coefficient}")]
33    NonFiniteCoefficient { coefficient: Complex64 },
34
35    /// A fermionic occupation must be either zero or one.
36    #[error("Invalid occupation at mode {index}: expected 0 or 1, got {value}")]
37    InvalidOccupation { index: usize, value: u8 },
38    /// Errors originating from quantum circuit operations, such as unsupported gates
39    /// or symbolic parameters.
40    #[error(transparent)]
41    CircuitError(#[from] CircuitError),
42
43    /// Thrown when the number of qubits of an operator (e.g., Hamiltonian) does not match
44    /// the number of qubits of the quantum state being measured.
45    #[error("Qubit count mismatch: expected {expected}, got {actual}")]
46    QubitMismatch { expected: usize, actual: usize },
47
48    /// Thrown when the dimensions of matrices or vectors do not match expectations
49    /// (e.g., when multiplying matrices of incompatible shapes).
50    #[error("Dimension mismatch: expected {expected}, got {actual}")]
51    DimensionMismatch { expected: usize, actual: usize },
52
53    /// Thrown when a state vector or density matrix has an invalid length
54    /// (e.g., its length is not a power of 2).
55    #[error("Invalid state dimension: length {0} is not a power of 2")]
56    InvalidStateDimension(usize),
57
58    /// Thrown when a probability value is mathematically invalid (e.g., < 0 or > 1).
59    #[error("Invalid probability value: {0}")]
60    InvalidProbability(f64),
61
62    /// Thrown when attempting to access a qubit or amplitude index that is out of bounds.
63    #[error("Index out of bounds: index {index}, max {max}")]
64    IndexOutOfBounds { index: usize, max: usize },
65
66    /// Thrown when an operation is requested but not supported by the simulation backend.
67    #[error("Unsupported simulation operation: {0}")]
68    UnsupportedOperation(String),
69
70    /// Thrown when parsing a Pauli string fails.
71    #[error(transparent)]
72    PauliStringParseError(#[from] PauliStringParseError),
73
74    /// Thrown when an explicitly provided quantum state is not normalized
75    /// (i.e., trace or norm is not 1).
76    #[error("State is not normalized")]
77    NotNormalized,
78
79    /// Thrown when an operator is expected to be Hermitian but is not
80    /// (e.g., a non-Hermitian Hamiltonian or density matrix).
81    #[error("Operator is not Hermitian")]
82    NotHermitian,
83
84    /// Thrown when a density matrix is expected to be positive semidefinite but is not.
85    #[error("Density matrix is not positive semidefinite")]
86    NotPositiveSemidefinite,
87
88    /// Thrown when a parameter value is invalid.
89    #[error("Invalid parameter value: {0}")]
90    InvalidParameterValue(String),
91
92    /// Thrown when a subsystem specification is invalid for entanglement calculations.
93    #[error("Invalid subsystem: {0}")]
94    InvalidSubsystem(String),
95
96    /// Thrown when an operation requires a specific dimension that is not met.
97    #[error("Unsupported dimension: expected {expected}, got {actual}")]
98    UnsupportedDimension { expected: usize, actual: usize },
99
100    /// Thrown when a gate is applied to a [`StabilizerState`] but is not a Clifford gate
101    /// (i.e., it does not map the Pauli group to itself under conjugation).
102    /// Examples: T, T†, Rx(θ) for generic θ.
103    ///
104    /// Use [`crate::qis::Statevector`] for universal (non-Clifford) simulation.
105    #[error("Non-Clifford gate: {0}")]
106    NonCliffordGate(String),
107}
108
109pub(crate) fn validate_coefficient(coefficient: Complex64) -> Result<(), QisError> {
110    if coefficient.re.is_finite() && coefficient.im.is_finite() {
111        Ok(())
112    } else {
113        Err(QisError::NonFiniteCoefficient { coefficient })
114    }
115}
116
117/// Error type for parsing PauliString from a string representation.
118#[derive(Debug, Clone, PartialEq, Eq, Error)]
119pub enum PauliStringParseError {
120    /// The string provided for parsing is empty.
121    #[error("empty string")]
122    EmptyString,
123
124    /// The string contains an invalid or unrecognized character.
125    #[error("invalid character '{0}'")]
126    InvalidCharacter(char),
127
128    /// The string only contains a phase but lacks any Pauli operators.
129    #[error("no Pauli operators specified")]
130    NoOperators,
131}