use thiserror::Error;
pub type Result<T> = std::result::Result<T, NeuralDecoderError>;
#[derive(Error, Debug)]
pub enum NeuralDecoderError {
#[error("Invalid syndrome dimensions: expected {expected}x{expected}, got {actual_rows}x{actual_cols}")]
InvalidSyndromeDimension {
expected: usize,
actual_rows: usize,
actual_cols: usize,
},
#[error("Invalid embedding dimension: expected {expected}, got {actual}")]
InvalidEmbeddingDimension {
expected: usize,
actual: usize,
},
#[error("Invalid hidden state dimension: expected {expected}, got {actual}")]
InvalidHiddenDimension {
expected: usize,
actual: usize,
},
#[error("Embedding dimension {embed_dim} must be divisible by number of heads {num_heads}")]
InvalidAttentionHeads {
embed_dim: usize,
num_heads: usize,
},
#[error("Detector graph is empty")]
EmptyGraph,
#[error("Invalid detector index: {0}")]
InvalidDetector(usize),
#[error("Invalid boundary type: {0}")]
InvalidBoundary(String),
#[error("Decoding failed: {0}")]
DecodingFailed(String),
#[error("Feature fusion error: {0}")]
FusionError(String),
#[error("MinCut integration error: {0}")]
MinCutError(String),
#[error("Shape mismatch: expected {expected:?}, got {actual:?}")]
ShapeMismatch {
expected: Vec<usize>,
actual: Vec<usize>,
},
#[error("Numerical instability detected: {0}")]
NumericalInstability(String),
#[error("Configuration error: {0}")]
ConfigError(String),
#[error("Internal error: {0}")]
InternalError(String),
}
impl NeuralDecoderError {
pub fn syndrome_dim(expected: usize, rows: usize, cols: usize) -> Self {
Self::InvalidSyndromeDimension {
expected,
actual_rows: rows,
actual_cols: cols,
}
}
pub fn embed_dim(expected: usize, actual: usize) -> Self {
Self::InvalidEmbeddingDimension { expected, actual }
}
pub fn hidden_dim(expected: usize, actual: usize) -> Self {
Self::InvalidHiddenDimension { expected, actual }
}
pub fn attention_heads(embed_dim: usize, num_heads: usize) -> Self {
Self::InvalidAttentionHeads {
embed_dim,
num_heads,
}
}
pub fn shape_mismatch(expected: Vec<usize>, actual: Vec<usize>) -> Self {
Self::ShapeMismatch { expected, actual }
}
pub fn is_recoverable(&self) -> bool {
matches!(
self,
Self::InvalidDetector(_)
| Self::InvalidBoundary(_)
| Self::ConfigError(_)
)
}
pub fn is_dimension_error(&self) -> bool {
matches!(
self,
Self::InvalidSyndromeDimension { .. }
| Self::InvalidEmbeddingDimension { .. }
| Self::InvalidHiddenDimension { .. }
| Self::InvalidAttentionHeads { .. }
| Self::ShapeMismatch { .. }
)
}
}
impl From<ruvector_mincut::MinCutError> for NeuralDecoderError {
fn from(err: ruvector_mincut::MinCutError) -> Self {
Self::MinCutError(err.to_string())
}
}
impl From<String> for NeuralDecoderError {
fn from(msg: String) -> Self {
Self::InternalError(msg)
}
}
impl From<&str> for NeuralDecoderError {
fn from(msg: &str) -> Self {
Self::InternalError(msg.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = NeuralDecoderError::syndrome_dim(5, 3, 4);
assert!(err.to_string().contains("5"));
assert!(err.to_string().contains("3"));
assert!(err.to_string().contains("4"));
let err = NeuralDecoderError::embed_dim(128, 64);
assert!(err.to_string().contains("128"));
assert!(err.to_string().contains("64"));
}
#[test]
fn test_is_recoverable() {
assert!(NeuralDecoderError::InvalidDetector(0).is_recoverable());
assert!(NeuralDecoderError::InvalidBoundary("test".to_string()).is_recoverable());
assert!(!NeuralDecoderError::EmptyGraph.is_recoverable());
assert!(!NeuralDecoderError::DecodingFailed("test".to_string()).is_recoverable());
}
#[test]
fn test_is_dimension_error() {
assert!(NeuralDecoderError::syndrome_dim(5, 3, 4).is_dimension_error());
assert!(NeuralDecoderError::embed_dim(128, 64).is_dimension_error());
assert!(NeuralDecoderError::attention_heads(128, 3).is_dimension_error());
assert!(!NeuralDecoderError::EmptyGraph.is_dimension_error());
}
#[test]
fn test_from_string() {
let err: NeuralDecoderError = "test error".into();
assert!(matches!(err, NeuralDecoderError::InternalError(_)));
assert!(err.to_string().contains("test error"));
}
}