Error Handling
Comprehensive error handling system for LogosQ using Result types and custom error enums.
Overview
The error module provides a robust error handling system for the LogosQ library. All operations that can fail return Result<T, LogosQError> instead of panicking, allowing for proper error propagation and handling.
Error Type
pub enum LogosQError {
InvalidQubitIndex { index: usize, num_qubits: usize },
InvalidStateDimension { dimension: usize },
DimensionMismatch { expected: usize, actual: usize },
InvalidGateMatrix { expected: Vec<usize>, actual: Vec<usize> },
ParameterCountMismatch { expected: usize, actual: usize },
CircuitQubitMismatch { circuit_qubits: usize, state_qubits: usize },
InvalidProbability { value: f64 },
InvalidAngle { value: f64 },
MeasurementError { message: String },
OptimizationError { message: String },
GradientError { message: String },
}
Result Type Alias
For convenience, the module provides a type alias:
pub type Result<T> = std::result::Result<T, LogosQError>;
Error Variants
InvalidQubitIndex
Occurs when a qubit index is out of range.
// Error message: "Invalid qubit index: 5 (must be < 3)"
LogosQError::InvalidQubitIndex { index: 5, num_qubits: 3 }
Example:
use logosq::prelude::*;
let mut circuit = Circuit::new(3);
match circuit.x(5) {
Ok(_) => println!("Gate added"),
Err(LogosQError::InvalidQubitIndex { index, num_qubits }) => {
eprintln!("Qubit {} is invalid for {} qubit circuit", index, num_qubits);
}
Err(e) => eprintln!("Other error: {}", e),
}
InvalidStateDimension
Occurs when a state vector has an invalid dimension (not a power of 2).
// Error message: "Invalid state dimension: 5 (must be a power of 2)"
LogosQError::InvalidStateDimension { dimension: 5 }
DimensionMismatch
Occurs when dimensions don't match expectations.
// Error message: "Dimension mismatch: expected 4, got 8"
LogosQError::DimensionMismatch { expected: 4, actual: 8 }
CircuitQubitMismatch
Occurs when executing a circuit on a state with different qubit counts.
// Error message: "Circuit qubit count mismatch: circuit has 3, state has 2"
LogosQError::CircuitQubitMismatch { circuit_qubits: 3, state_qubits: 2 }
Error Handling Patterns
Using the ? Operator
The most common pattern for error handling:
use logosq::prelude::*;
fn create_bell_state() -> Result<State> {
let mut circuit = Circuit::new(2);
circuit.h(0)?; // Propagates error if qubit index is invalid
circuit.cnot(0, 1)?;
let mut state = State::zero_state(2);
circuit.execute(&mut state)?;
Ok(state)
}
Pattern Matching
For more detailed error handling:
use logosq::prelude::*;
match circuit.add_operation(gate, vec![5], "Gate") {
Ok(_) => println!("Success"),
Err(LogosQError::InvalidQubitIndex { index, num_qubits }) => {
eprintln!("Invalid qubit {} for {} qubit circuit", index, num_qubits);
}
Err(e) => eprintln!("Error: {}", e),
}
Unwrapping (for Examples/Testing)
In examples or tests where errors are unexpected:
use logosq::prelude::*;
let mut circuit = Circuit::new(2);
circuit.h(0).unwrap(); // Panics on error - use only when error is impossible
circuit.cnot(0, 1).unwrap();
Converting to Option
If you want to ignore errors:
use logosq::prelude::*;
let result = circuit.add_operation(gate, vec![0], "Gate").ok();
if result.is_some() {
println!("Gate added successfully");
}
Best Practices
- Always handle Results: Don't ignore
Resultreturn types - Use
?for error propagation: In functions that returnResult - Provide context: When handling errors, log or display helpful messages
- Match specific errors: Use pattern matching for different error types
- Avoid unwrap in production: Use
unwrap()only in tests or examples
Examples
Complete Error Handling Example
use logosq::prelude::*;
fn quantum_algorithm() -> Result<()> {
// Create circuit
let mut circuit = Circuit::new(3)?;
// Add gates with error handling
circuit.h(0)?;
circuit.cnot(0, 1)?;
circuit.ry(2, std::f64::consts::PI / 4.0)?;
// Create and execute state
let mut state = State::new(
Array1::from_vec(vec![Complex64::new(1.0, 0.0); 8]),
Some(3)
)?;
circuit.execute(&mut state)?;
// Measure with error handling
let result = state.measure_qubit(0)?;
println!("Measurement: {}", result);
Ok(())
}
fn main() {
match quantum_algorithm() {
Ok(_) => println!("Algorithm completed successfully"),
Err(e) => eprintln!("Error: {}", e),
}
}
Error Handling in Loops
use logosq::prelude::*;
fn add_gates_safely(circuit: &mut Circuit, qubits: &[usize]) -> Result<()> {
for &qubit in qubits {
circuit.h(qubit)?; // Stops on first error
}
Ok(())
}
Integration with Other Modules
All modules in LogosQ use LogosQError for consistent error handling:
- State:
State::new(),measure_qubit(),tensor_product()returnResult - Circuit:
execute(),add_operation(),compose()returnResult - Gates:
Gate::apply()returnsResult - Optimization: VQE, gradient methods return
Result
This unified error system makes it easy to handle errors across the entire library consistently.