1use thiserror::Error;
7
8pub type Result<T> = std::result::Result<T, VqNasError>;
10
11#[derive(Error, Debug)]
13pub enum VqNasError {
14 #[error("Search space error: {0}")]
16 SearchSpace(#[from] SearchSpaceError),
17
18 #[error("Encoding error: {0}")]
20 Encoding(#[from] EncodingError),
21
22 #[error("Search error: {0}")]
24 Search(#[from] SearchError),
25
26 #[error("Evaluation error: {0}")]
28 Evaluation(#[from] EvaluationError),
29
30 #[error("Circuit error: {0}")]
32 Circuit(#[from] CircuitError),
33
34 #[error("Serialization error: {0}")]
36 Serialization(String),
37
38 #[error("Invalid configuration: {0}")]
40 InvalidConfiguration(String),
41
42 #[error("Resource exhaustion: {0}")]
44 ResourceExhaustion(String),
45}
46
47#[derive(Error, Debug, Clone, PartialEq)]
49pub enum SearchSpaceError {
50 #[error("Invalid qubit count: {0}. Must be between 1 and {1}")]
52 InvalidQubitCount(usize, usize),
53
54 #[error("Invalid layer depth: {0}. Must be between 1 and {1}")]
56 InvalidLayerDepth(usize, usize),
57
58 #[error("Invalid gate: {0}")]
60 InvalidGate(String),
61
62 #[error("Connectivity constraint violated: qubits {0} and {1} are not connected")]
64 ConnectivityViolation(usize, usize),
65
66 #[error("Gate set cannot be empty")]
68 EmptyGateSet,
69
70 #[error("Invalid template: {0}")]
72 InvalidTemplate(String),
73
74 #[error("Qubit index {0} out of bounds for {1} qubits")]
76 QubitOutOfBounds(usize, usize),
77}
78
79#[derive(Error, Debug, Clone, PartialEq)]
81pub enum EncodingError {
82 #[error("Invalid encoding dimension: expected {expected}, got {got}")]
84 InvalidDimension { expected: usize, got: usize },
85
86 #[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 #[error("Encoding value {value} out of range [{min}, {max}]")]
96 OutOfRange { value: f64, min: f64, max: f64 },
97
98 #[error("Failed to decode architecture: {0}")]
100 DecodingFailed(String),
101
102 #[error("Invalid embedding dimension: {0}")]
104 InvalidEmbeddingDimension(usize),
105}
106
107#[derive(Error, Debug, Clone, PartialEq)]
109pub enum SearchError {
110 #[error("Search budget exhausted after {0} evaluations")]
112 BudgetExhausted(usize),
113
114 #[error("No valid architectures found in search space")]
116 NoValidArchitectures,
117
118 #[error("Search failed to converge after {iterations} iterations (best score: {best_score})")]
120 ConvergenceFailure { iterations: usize, best_score: f64 },
121
122 #[error("Invalid search configuration: {0}")]
124 InvalidConfiguration(String),
125
126 #[error("Population size {0} too small, minimum is {1}")]
128 PopulationTooSmall(usize, usize),
129
130 #[error("Invalid mutation rate {0}: must be in [0, 1]")]
132 InvalidMutationRate(f64),
133
134 #[error("Early stopping triggered at iteration {iteration} (no improvement for {patience} iterations)")]
136 EarlyStopping { iteration: usize, patience: usize },
137}
138
139#[derive(Error, Debug, Clone, PartialEq)]
141pub enum EvaluationError {
142 #[error("Invalid metric value: {metric} = {value}")]
144 InvalidMetricValue { metric: String, value: f64 },
145
146 #[error("Evaluation timed out after {0} seconds")]
148 Timeout(u64),
149
150 #[error("Insufficient samples: got {got}, need {required}")]
152 InsufficientSamples { got: usize, required: usize },
153
154 #[error("Numerical instability in {operation}: {details}")]
156 NumericalInstability { operation: String, details: String },
157
158 #[error("Invalid state vector: dimension {0} for {1} qubits (expected {2})")]
160 InvalidStateVector(usize, usize, usize),
161
162 #[error("Hardware cost estimation failed: {0}")]
164 HardwareCostError(String),
165}
166
167#[derive(Error, Debug, Clone, PartialEq)]
169pub enum CircuitError {
170 #[error("Invalid parameter value at index {index}: {value}")]
172 InvalidParameter { index: usize, value: f64 },
173
174 #[error("Missing parameter at index {0}")]
176 MissingParameter(usize),
177
178 #[error("Cannot apply {gate} to qubit(s) {qubits:?}")]
180 InvalidGateApplication { gate: String, qubits: Vec<usize> },
181
182 #[error("Circuit depth {depth} exceeds maximum {max_depth}")]
184 CircuitTooDeep { depth: usize, max_depth: usize },
185
186 #[error("Gate count {count} exceeds maximum {max_count}")]
188 TooManyGates { count: usize, max_count: usize },
189
190 #[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}