ruqu_vq_nas/
error.rs

1//! Error types for VQ-NAS operations.
2//!
3//! This module provides comprehensive error handling for quantum neural
4//! architecture search operations, including validation, search, and evaluation errors.
5
6use thiserror::Error;
7
8/// Result type alias for VQ-NAS operations.
9pub type Result<T> = std::result::Result<T, VqNasError>;
10
11/// Main error type for VQ-NAS operations.
12#[derive(Error, Debug)]
13pub enum VqNasError {
14    /// Search space configuration error.
15    #[error("Search space error: {0}")]
16    SearchSpace(#[from] SearchSpaceError),
17
18    /// Architecture encoding error.
19    #[error("Encoding error: {0}")]
20    Encoding(#[from] EncodingError),
21
22    /// Search algorithm error.
23    #[error("Search error: {0}")]
24    Search(#[from] SearchError),
25
26    /// Circuit evaluation error.
27    #[error("Evaluation error: {0}")]
28    Evaluation(#[from] EvaluationError),
29
30    /// Circuit building error.
31    #[error("Circuit error: {0}")]
32    Circuit(#[from] CircuitError),
33
34    /// Serialization/deserialization error.
35    #[error("Serialization error: {0}")]
36    Serialization(String),
37
38    /// Invalid configuration.
39    #[error("Invalid configuration: {0}")]
40    InvalidConfiguration(String),
41
42    /// Resource exhaustion.
43    #[error("Resource exhaustion: {0}")]
44    ResourceExhaustion(String),
45}
46
47/// Errors related to search space definition.
48#[derive(Error, Debug, Clone, PartialEq)]
49pub enum SearchSpaceError {
50    /// Invalid number of qubits.
51    #[error("Invalid qubit count: {0}. Must be between 1 and {1}")]
52    InvalidQubitCount(usize, usize),
53
54    /// Invalid layer depth.
55    #[error("Invalid layer depth: {0}. Must be between 1 and {1}")]
56    InvalidLayerDepth(usize, usize),
57
58    /// Invalid gate specification.
59    #[error("Invalid gate: {0}")]
60    InvalidGate(String),
61
62    /// Connectivity constraint violation.
63    #[error("Connectivity constraint violated: qubits {0} and {1} are not connected")]
64    ConnectivityViolation(usize, usize),
65
66    /// Empty gate set.
67    #[error("Gate set cannot be empty")]
68    EmptyGateSet,
69
70    /// Invalid template.
71    #[error("Invalid template: {0}")]
72    InvalidTemplate(String),
73
74    /// Qubit index out of bounds.
75    #[error("Qubit index {0} out of bounds for {1} qubits")]
76    QubitOutOfBounds(usize, usize),
77}
78
79/// Errors related to architecture encoding.
80#[derive(Error, Debug, Clone, PartialEq)]
81pub enum EncodingError {
82    /// Invalid architecture vector dimension.
83    #[error("Invalid encoding dimension: expected {expected}, got {got}")]
84    InvalidDimension { expected: usize, got: usize },
85
86    /// Invalid discrete choice.
87    #[error("Invalid choice {choice} at position {position}: must be < {max_choices}")]
88    InvalidChoice {
89        position: usize,
90        choice: usize,
91        max_choices: usize,
92    },
93
94    /// Encoding out of range.
95    #[error("Encoding value {value} out of range [{min}, {max}]")]
96    OutOfRange { value: f64, min: f64, max: f64 },
97
98    /// Failed to decode architecture.
99    #[error("Failed to decode architecture: {0}")]
100    DecodingFailed(String),
101
102    /// Invalid embedding dimension.
103    #[error("Invalid embedding dimension: {0}")]
104    InvalidEmbeddingDimension(usize),
105}
106
107/// Errors related to search algorithms.
108#[derive(Error, Debug, Clone, PartialEq)]
109pub enum SearchError {
110    /// Search budget exhausted.
111    #[error("Search budget exhausted after {0} evaluations")]
112    BudgetExhausted(usize),
113
114    /// No valid architectures found.
115    #[error("No valid architectures found in search space")]
116    NoValidArchitectures,
117
118    /// Convergence failure.
119    #[error("Search failed to converge after {iterations} iterations (best score: {best_score})")]
120    ConvergenceFailure { iterations: usize, best_score: f64 },
121
122    /// Invalid search configuration.
123    #[error("Invalid search configuration: {0}")]
124    InvalidConfiguration(String),
125
126    /// Population too small.
127    #[error("Population size {0} too small, minimum is {1}")]
128    PopulationTooSmall(usize, usize),
129
130    /// Invalid mutation rate.
131    #[error("Invalid mutation rate {0}: must be in [0, 1]")]
132    InvalidMutationRate(f64),
133
134    /// Early stopping triggered.
135    #[error("Early stopping triggered at iteration {iteration} (no improvement for {patience} iterations)")]
136    EarlyStopping { iteration: usize, patience: usize },
137}
138
139/// Errors related to circuit evaluation.
140#[derive(Error, Debug, Clone, PartialEq)]
141pub enum EvaluationError {
142    /// Invalid metric value.
143    #[error("Invalid metric value: {metric} = {value}")]
144    InvalidMetricValue { metric: String, value: f64 },
145
146    /// Evaluation timeout.
147    #[error("Evaluation timed out after {0} seconds")]
148    Timeout(u64),
149
150    /// Insufficient samples.
151    #[error("Insufficient samples: got {got}, need {required}")]
152    InsufficientSamples { got: usize, required: usize },
153
154    /// Numerical instability.
155    #[error("Numerical instability in {operation}: {details}")]
156    NumericalInstability { operation: String, details: String },
157
158    /// Invalid state vector.
159    #[error("Invalid state vector: dimension {0} for {1} qubits (expected {2})")]
160    InvalidStateVector(usize, usize, usize),
161
162    /// Hardware cost estimation failed.
163    #[error("Hardware cost estimation failed: {0}")]
164    HardwareCostError(String),
165}
166
167/// Errors related to circuit building.
168#[derive(Error, Debug, Clone, PartialEq)]
169pub enum CircuitError {
170    /// Invalid parameter value.
171    #[error("Invalid parameter value at index {index}: {value}")]
172    InvalidParameter { index: usize, value: f64 },
173
174    /// Missing parameter.
175    #[error("Missing parameter at index {0}")]
176    MissingParameter(usize),
177
178    /// Invalid gate application.
179    #[error("Cannot apply {gate} to qubit(s) {qubits:?}")]
180    InvalidGateApplication { gate: String, qubits: Vec<usize> },
181
182    /// Circuit too deep.
183    #[error("Circuit depth {depth} exceeds maximum {max_depth}")]
184    CircuitTooDeep { depth: usize, max_depth: usize },
185
186    /// Too many gates.
187    #[error("Gate count {count} exceeds maximum {max_count}")]
188    TooManyGates { count: usize, max_count: usize },
189
190    /// Parameter count mismatch.
191    #[error("Parameter count mismatch: circuit has {expected} parameters, got {got}")]
192    ParameterCountMismatch { expected: usize, got: usize },
193}
194
195impl From<serde_json::Error> for VqNasError {
196    fn from(err: serde_json::Error) -> Self {
197        VqNasError::Serialization(err.to_string())
198    }
199}
200
201#[cfg(test)]
202mod tests {
203    use super::*;
204
205    #[test]
206    fn test_search_space_error_display() {
207        let err = SearchSpaceError::InvalidQubitCount(100, 50);
208        assert!(err.to_string().contains("100"));
209        assert!(err.to_string().contains("50"));
210    }
211
212    #[test]
213    fn test_encoding_error_display() {
214        let err = EncodingError::InvalidDimension {
215            expected: 10,
216            got: 5,
217        };
218        assert!(err.to_string().contains("10"));
219        assert!(err.to_string().contains("5"));
220    }
221
222    #[test]
223    fn test_search_error_display() {
224        let err = SearchError::BudgetExhausted(1000);
225        assert!(err.to_string().contains("1000"));
226    }
227
228    #[test]
229    fn test_evaluation_error_display() {
230        let err = EvaluationError::InvalidMetricValue {
231            metric: "expressibility".to_string(),
232            value: -0.5,
233        };
234        assert!(err.to_string().contains("expressibility"));
235    }
236
237    #[test]
238    fn test_circuit_error_display() {
239        let err = CircuitError::InvalidParameter {
240            index: 5,
241            value: f64::NAN,
242        };
243        assert!(err.to_string().contains("5"));
244    }
245
246    #[test]
247    fn test_error_conversion() {
248        let search_err = SearchSpaceError::EmptyGateSet;
249        let vqnas_err: VqNasError = search_err.into();
250        assert!(matches!(vqnas_err, VqNasError::SearchSpace(_)));
251    }
252
253    #[test]
254    fn test_result_type() {
255        fn example_fn() -> Result<i32> {
256            Err(VqNasError::InvalidConfiguration("test".to_string()))
257        }
258        assert!(example_fn().is_err());
259    }
260}