Validation API¶
The qubitos.validation module provides validation utilities for quantum-specific data types with configurable strictness levels.
Overview¶
The validation system provides:
- Quantum-specific validators: Hermiticity, unitarity, fidelity ranges
- Physics constraints: T1/T2 coherence time relationships
- Strictness modes: STRICT (raises exceptions) or LENIENT (logs warnings)
Quick Start¶
from qubitos.validation import (
validate_unitary,
validate_fidelity,
)
import numpy as np
# Validate a unitary matrix
U = np.array([[0, 1], [1, 0]], dtype=complex) # Pauli-X
result = validate_unitary(U)
print(f"Valid: {result.valid}")
print(f"Errors: {result.errors}")
# Validate fidelity value
result = validate_fidelity(0.999)
print(f"Valid: {result.valid}")
Strictness Modes¶
STRICT Mode (Default)¶
Validation failures raise exceptions:
from qubitos.validation import set_strictness, Strictness, ValidationError
set_strictness(Strictness.STRICT)
try:
result = validate_fidelity(1.5) # Invalid: > 1
except ValidationError as e:
print(f"Error: {e}")
LENIENT Mode¶
Validation failures log warnings but continue:
set_strictness(Strictness.LENIENT)
result = validate_fidelity(1.5) # Logs warning, continues
print(f"Valid: {result.valid}") # False
Environment Variable¶
Set strictness via environment:
# Strict mode (default)
export QUBITOS_STRICT_VALIDATION=true
# Lenient mode
export QUBITOS_STRICT_VALIDATION=false
Matrix Validators¶
Hermitian Matrices¶
Validates \(H = H^\dagger\):
from qubitos.validation import validate_hermitian
import numpy as np
# Valid Hermitian matrix
H = np.array([[1, 1j], [-1j, 2]], dtype=complex)
result = validate_hermitian(H)
print(f"Hermitian: {result.valid}") # True
# Invalid (not Hermitian)
H_bad = np.array([[1, 1j], [1j, 2]], dtype=complex)
result = validate_hermitian(H_bad)
print(f"Hermitian: {result.valid}") # False
print(f"Errors: {result.errors}")
Unitary Matrices¶
Validates \(U^\dagger U = I\):
from qubitos.validation import validate_unitary
import numpy as np
# Valid unitary (Hadamard)
H = np.array([[1, 1], [1, -1]], dtype=complex) / np.sqrt(2)
result = validate_unitary(H)
print(f"Unitary: {result.valid}") # True
# With custom tolerance
result = validate_unitary(H, tolerance=1e-12)
Fidelity Validation¶
Validates fidelity is in range [0, 1]:
from qubitos.validation import validate_fidelity
# Valid fidelity
result = validate_fidelity(0.999, name="gate_fidelity")
print(f"Valid: {result.valid}")
# Invalid cases
validate_fidelity(-0.1) # Error: < 0
validate_fidelity(1.5) # Error: > 1
validate_fidelity(float('nan')) # Error: NaN
# Warning for suspicious values
result = validate_fidelity(0.3) # Warning: suspiciously low
print(f"Warnings: {result.warnings}")
Pulse Validation¶
Validate pulse envelope arrays:
from qubitos.validation import validate_pulse_envelope
import numpy as np
envelope = np.random.randn(100) * 10 # Random pulse
result = validate_pulse_envelope(
envelope,
max_amplitude=50.0, # MHz
num_time_steps=100,
name="I_envelope",
)
print(f"Valid: {result.valid}")
print(f"Errors: {result.errors}")
print(f"Warnings: {result.warnings}")
Validate Both I and Q¶
Validate each quadrature envelope independently:
from qubitos.validation import validate_pulse_envelope
i_result = validate_pulse_envelope(i_pulse, 100.0, 100, name="I envelope")
q_result = validate_pulse_envelope(q_pulse, 100.0, 100, name="Q envelope")
valid = i_result.valid and q_result.valid
Calibration Validation¶
T1/T2 Coherence Times¶
Physics constraint: T2 ≤ 2·T1
from qubitos.validation import validate_calibration_t1_t2
# Valid
result = validate_calibration_t1_t2(t1_us=100, t2_us=80)
print(f"Valid: {result.valid}") # True
# Warning (T2 > T1 is unusual)
result = validate_calibration_t1_t2(t1_us=100, t2_us=120)
print(f"Warnings: {result.warnings}")
# Error (T2 > 2*T1 violates physics)
result = validate_calibration_t1_t2(t1_us=100, t2_us=250)
print(f"Errors: {result.errors}")
Full Calibration Validation¶
Compose the T1/T2 and fidelity validators to check a full qubit record:
from qubitos.validation import validate_calibration_t1_t2, validate_fidelity
t_result = validate_calibration_t1_t2(t1_us=100, t2_us=80)
ro_result = validate_fidelity(0.99, name="readout_fidelity")
gate_result = validate_fidelity(0.999, name="gate_fidelity")
valid = t_result.valid and ro_result.valid and gate_result.valid
Hamiltonian Validation¶
A Hamiltonian must be Hermitian. Use validate_hermitian with a descriptive
name for clearer error messages:
from qubitos.validation import validate_hermitian
import numpy as np
H = np.array([[1, 0], [0, -1]], dtype=complex)
result = validate_hermitian(H, name="Hamiltonian")
print(f"Valid Hamiltonian: {result.valid}")
ValidationResult¶
All validators return a ValidationResult object:
from qubitos.validation import ValidationResult
result = ValidationResult(
valid=True,
errors=[],
warnings=["Value is close to limit"],
)
# Boolean conversion
if result:
print("Validation passed")
# Access details
print(result.valid)
print(result.errors)
print(result.warnings)
API Reference¶
Enums and Types¶
qubitos.validation.Strictness ¶
Bases: Enum
Validation strictness level.
qubitos.validation.ValidationResult
dataclass
¶
Result of a validation check.
qubitos.validation.ValidationError ¶
Strictness Control¶
qubitos.validation.get_strictness ¶
Get current validation strictness.
Source code in src/qubitos/validation/__init__.py
qubitos.validation.set_strictness ¶
Matrix Validators¶
qubitos.validation.validate_hermitian ¶
validate_hermitian(matrix: ndarray, tolerance: float = 1e-10, name: str = 'matrix') -> ValidationResult
Validate that a matrix is Hermitian (H = H^dag).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
matrix
|
ndarray
|
Complex numpy array to validate |
required |
tolerance
|
float
|
Maximum allowed deviation from Hermiticity |
1e-10
|
name
|
str
|
Name of the matrix for error messages |
'matrix'
|
Returns:
| Type | Description |
|---|---|
ValidationResult
|
ValidationResult with any errors found |
Source code in src/qubitos/validation/__init__.py
qubitos.validation.validate_unitary ¶
validate_unitary(matrix: ndarray, tolerance: float = 1e-10, name: str = 'matrix') -> ValidationResult
Validate that a matrix is unitary (U^dag @ U = I).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
matrix
|
ndarray
|
Complex numpy array to validate |
required |
tolerance
|
float
|
Maximum allowed deviation from unitarity |
1e-10
|
name
|
str
|
Name of the matrix for error messages |
'matrix'
|
Returns:
| Type | Description |
|---|---|
ValidationResult
|
ValidationResult with any errors found |
Source code in src/qubitos/validation/__init__.py
Value Validators¶
qubitos.validation.validate_fidelity ¶
Validate that a fidelity value is in valid range [0, 1].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fidelity
|
float
|
Fidelity value to validate |
required |
name
|
str
|
Name for error messages |
'fidelity'
|
Returns:
| Type | Description |
|---|---|
ValidationResult
|
ValidationResult with any errors found |
Source code in src/qubitos/validation/__init__.py
qubitos.validation.validate_pulse_envelope ¶
validate_pulse_envelope(envelope: ndarray, max_amplitude: float, num_time_steps: int, name: str = 'envelope') -> ValidationResult
Validate a pulse envelope array.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
envelope
|
ndarray
|
Pulse amplitude array |
required |
max_amplitude
|
float
|
Maximum allowed amplitude |
required |
num_time_steps
|
int
|
Expected number of time steps |
required |
name
|
str
|
Name for error messages |
'envelope'
|
Returns:
| Type | Description |
|---|---|
ValidationResult
|
ValidationResult with any errors found |
Source code in src/qubitos/validation/__init__.py
qubitos.validation.validate_calibration_t1_t2 ¶
Validate T1/T2 coherence times.
Physics constraint: T2 <= 2*T1 (and typically T2 < T1 in practice)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
t1_us
|
float
|
T1 relaxation time in microseconds |
required |
t2_us
|
float
|
T2 dephasing time in microseconds |
required |
Returns:
| Type | Description |
|---|---|
ValidationResult
|
ValidationResult with any errors found |
Source code in src/qubitos/validation/__init__.py
Convenience Functions¶
qubitos.validation.validate_pulse_physics ¶
validate_pulse_physics(duration_ns: float, drive_amplitude_mhz: float, frequency_ghz: float = 5.0, anharmonicity_mhz: float = -330.0) -> ValidationResult
Physics-aware validation for pulse parameters.
Checks: 1. Pulse duration vs Rabi period — warns if shorter than one cycle. 2. Drive amplitude vs anharmonicity — warns if strong enough to excite the 1→2 transition in a transmon.
The Rabi frequency is Ω = drive_amplitude (in angular frequency units). One Rabi cycle = 1/Ω. If duration < one cycle, the pulse cannot complete a full rotation.
For transmon qubits, the 0→1 drive should satisfy Ω << |α| where α is the anharmonicity, otherwise leakage to |2⟩ occurs.
Koch et al. (2007), Phys. Rev. A 76, 042319.
DOI: 10.1103/PhysRevA.76.042319
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
duration_ns
|
float
|
Pulse duration in nanoseconds. |
required |
drive_amplitude_mhz
|
float
|
Drive amplitude in MHz. |
required |
frequency_ghz
|
float
|
Qubit frequency in GHz (default 5.0). |
5.0
|
anharmonicity_mhz
|
float
|
Transmon anharmonicity in MHz (default -330). |
-330.0
|
Returns:
| Type | Description |
|---|---|
ValidationResult
|
ValidationResult with physics-based warnings. |
Source code in src/qubitos/validation/__init__.py
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | |