Skip to content

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)
  • AgentBible integration: Extended validation when available

Quick Start

from qubitos.validation import (
    validate_unitary,
    validate_fidelity,
    validate_hamiltonian,
)
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

from qubitos.validation import validate_pulse

result = validate_pulse(
    i_envelope=i_pulse,
    q_envelope=q_pulse,
    max_amplitude=100.0,
    num_time_steps=100,
)

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

from qubitos.validation import validate_calibration

result = validate_calibration(
    t1_us=100,
    t2_us=80,
    readout_fidelity=0.99,
    gate_fidelity=0.999,
)

Hamiltonian Validation

Convenience function combining Hermiticity check with optional AgentBible validators:

from qubitos.validation import validate_hamiltonian
import numpy as np

H = np.array([[1, 0], [0, -1]], dtype=complex)
result = validate_hamiltonian(H)
print(f"Valid Hamiltonian: {result.valid}")

AgentBible Integration

When AgentBible is installed, additional validation is available:

from qubitos.validation import (
    is_agentbible_available,
    AgentBibleValidator,
)

print(f"AgentBible available: {is_agentbible_available()}")

validator = AgentBibleValidator()

# Hamiltonian validation (with AgentBible extras if available)
result = validator.validate_hamiltonian(H)

# Pulse validation
result = validator.validate_pulse(i_envelope, q_envelope, max_amp, n_steps)

# Calibration validation
result = validator.validate_calibration(t1_us=100, t2_us=80)

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

ValidationResult(
    valid: bool, errors: list[str], warnings: list[str]
)

Result of a validation check.

qubitos.validation.ValidationError

ValidationError(
    message: str,
    field: str | None = None,
    value: Any = None,
)

Bases: Exception

Raised when validation fails in strict mode.

Source code in src/qubitos/validation/__init__.py
def __init__(self, message: str, field: str | None = None, value: Any = None):
    self.field = field
    self.value = value
    super().__init__(message)

Strictness Control

qubitos.validation.get_strictness

get_strictness() -> Strictness

Get current validation strictness.

Source code in src/qubitos/validation/__init__.py
def get_strictness() -> Strictness:
    """Get current validation strictness."""
    env_value = os.environ.get("QUBITOS_STRICT_VALIDATION", "true").lower()
    if env_value in ("false", "0", "no", "lenient"):
        return Strictness.LENIENT
    return _strictness

qubitos.validation.set_strictness

set_strictness(strictness: Strictness) -> None

Set validation strictness.

Source code in src/qubitos/validation/__init__.py
def set_strictness(strictness: Strictness) -> None:
    """Set validation strictness."""
    global _strictness
    _strictness = 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
def validate_hermitian(
    matrix: np.ndarray, tolerance: float = 1e-10, name: str = "matrix"
) -> ValidationResult:
    """Validate that a matrix is Hermitian (H = H^dag).

    Args:
        matrix: Complex numpy array to validate
        tolerance: Maximum allowed deviation from Hermiticity
        name: Name of the matrix for error messages

    Returns:
        ValidationResult with any errors found
    """
    errors = []
    warnings: list[str] = []

    if matrix.ndim != 2:
        errors.append(f"{name} must be 2-dimensional, got {matrix.ndim}D")
        return ValidationResult(False, errors, warnings)

    if matrix.shape[0] != matrix.shape[1]:
        errors.append(f"{name} must be square, got shape {matrix.shape}")
        return ValidationResult(False, errors, warnings)

    # Check Hermiticity: H - H^dag should be zero
    diff = matrix - matrix.conj().T
    max_deviation = np.max(np.abs(diff))

    if max_deviation > tolerance:
        errors.append(
            f"{name} is not Hermitian: max deviation {max_deviation:.2e} > tolerance {tolerance:.2e}"
        )
    elif max_deviation > tolerance / 100:
        warnings.append(f"{name} Hermiticity: deviation {max_deviation:.2e} is close to tolerance")

    return ValidationResult(len(errors) == 0, errors, warnings)

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
def validate_unitary(
    matrix: np.ndarray, tolerance: float = 1e-10, name: str = "matrix"
) -> ValidationResult:
    """Validate that a matrix is unitary (U^dag @ U = I).

    Args:
        matrix: Complex numpy array to validate
        tolerance: Maximum allowed deviation from unitarity
        name: Name of the matrix for error messages

    Returns:
        ValidationResult with any errors found
    """
    errors = []
    warnings: list[str] = []

    if matrix.ndim != 2:
        errors.append(f"{name} must be 2-dimensional, got {matrix.ndim}D")
        return ValidationResult(False, errors, warnings)

    if matrix.shape[0] != matrix.shape[1]:
        errors.append(f"{name} must be square, got shape {matrix.shape}")
        return ValidationResult(False, errors, warnings)

    # Check unitarity: U^dag @ U - I should be zero
    identity = np.eye(matrix.shape[0], dtype=complex)
    product = matrix.conj().T @ matrix
    diff = product - identity
    max_deviation = np.max(np.abs(diff))

    if max_deviation > tolerance:
        errors.append(
            f"{name} is not unitary: max deviation {max_deviation:.2e} > tolerance {tolerance:.2e}"
        )
    elif max_deviation > tolerance / 100:
        warnings.append(f"{name} unitarity: deviation {max_deviation:.2e} is close to tolerance")

    return ValidationResult(len(errors) == 0, errors, warnings)

Value Validators

qubitos.validation.validate_fidelity

validate_fidelity(
    fidelity: float, name: str = "fidelity"
) -> ValidationResult

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
def validate_fidelity(fidelity: float, name: str = "fidelity") -> ValidationResult:
    """Validate that a fidelity value is in valid range [0, 1].

    Args:
        fidelity: Fidelity value to validate
        name: Name for error messages

    Returns:
        ValidationResult with any errors found
    """
    errors = []
    warnings: list[str] = []

    if not isinstance(fidelity, (int, float)):
        errors.append(f"{name} must be a number, got {type(fidelity).__name__}")
        return ValidationResult(False, errors, warnings)

    if np.isnan(fidelity):
        errors.append(f"{name} is NaN")
    elif np.isinf(fidelity):
        errors.append(f"{name} is infinite")
    elif fidelity < 0:
        errors.append(f"{name} must be >= 0, got {fidelity}")
    elif fidelity > 1:
        errors.append(f"{name} must be <= 1, got {fidelity}")

    # Warn if suspiciously low
    if 0 <= fidelity < 0.5:
        warnings.append(f"{name} = {fidelity} is suspiciously low")

    return ValidationResult(len(errors) == 0, errors, warnings)

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
def validate_pulse_envelope(
    envelope: np.ndarray, max_amplitude: float, num_time_steps: int, name: str = "envelope"
) -> ValidationResult:
    """Validate a pulse envelope array.

    Args:
        envelope: Pulse amplitude array
        max_amplitude: Maximum allowed amplitude
        num_time_steps: Expected number of time steps
        name: Name for error messages

    Returns:
        ValidationResult with any errors found
    """
    errors = []
    warnings: list[str] = []

    if not isinstance(envelope, np.ndarray):
        envelope = np.array(envelope)

    # Check length
    if len(envelope) != num_time_steps:
        errors.append(f"{name} length {len(envelope)} != expected {num_time_steps}")

    # Check for NaN/Inf
    if np.any(np.isnan(envelope)):
        errors.append(f"{name} contains NaN values")
    if np.any(np.isinf(envelope)):
        errors.append(f"{name} contains infinite values")

    # Check amplitude bounds
    max_val = np.max(np.abs(envelope))
    if max_val > max_amplitude:
        errors.append(f"{name} max amplitude {max_val:.2f} exceeds limit {max_amplitude:.2f}")

    # Warn if pulse is very small (might be unintentional)
    if max_val < max_amplitude * 0.01:
        warnings.append(
            f"{name} max amplitude {max_val:.2e} is < 1% of limit - pulse may be too weak"
        )

    return ValidationResult(len(errors) == 0, errors, warnings)

qubitos.validation.validate_calibration_t1_t2

validate_calibration_t1_t2(
    t1_us: float, t2_us: float
) -> ValidationResult

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
def validate_calibration_t1_t2(t1_us: float, t2_us: float) -> ValidationResult:
    """Validate T1/T2 coherence times.

    Physics constraint: T2 <= 2*T1 (and typically T2 < T1 in practice)

    Args:
        t1_us: T1 relaxation time in microseconds
        t2_us: T2 dephasing time in microseconds

    Returns:
        ValidationResult with any errors found
    """
    errors = []
    warnings: list[str] = []

    # Basic range checks
    if t1_us <= 0:
        errors.append(f"T1 must be positive, got {t1_us}")
    if t2_us <= 0:
        errors.append(f"T2 must be positive, got {t2_us}")

    if errors:
        return ValidationResult(False, errors, warnings)

    # Physics constraint: T2 <= 2*T1
    if t2_us > 2 * t1_us:
        errors.append(f"T2 ({t2_us} us) > 2*T1 ({2 * t1_us} us) violates physics constraint")

    # Typically T2 < T1 in real systems
    if t2_us > t1_us:
        warnings.append(f"T2 ({t2_us} us) > T1 ({t1_us} us) is unusual - verify calibration")

    return ValidationResult(len(errors) == 0, errors, warnings)

Convenience Functions

qubitos.validation.validate_hamiltonian

validate_hamiltonian(
    matrix: ndarray, tolerance: float = 1e-10
) -> ValidationResult

Validate a Hamiltonian matrix using the default validator.

Source code in src/qubitos/validation/__init__.py
def validate_hamiltonian(matrix: np.ndarray, tolerance: float = 1e-10) -> ValidationResult:
    """Validate a Hamiltonian matrix using the default validator."""
    return default_validator.validate_hamiltonian(matrix, tolerance)

qubitos.validation.validate_pulse

validate_pulse(
    i_envelope: ndarray,
    q_envelope: ndarray,
    max_amplitude: float,
    num_time_steps: int,
) -> ValidationResult

Validate pulse envelopes using the default validator.

Source code in src/qubitos/validation/__init__.py
def validate_pulse(
    i_envelope: np.ndarray, q_envelope: np.ndarray, max_amplitude: float, num_time_steps: int
) -> ValidationResult:
    """Validate pulse envelopes using the default validator."""
    return default_validator.validate_pulse(i_envelope, q_envelope, max_amplitude, num_time_steps)

qubitos.validation.validate_calibration

validate_calibration(
    t1_us: float,
    t2_us: float,
    readout_fidelity: float | None = None,
    gate_fidelity: float | None = None,
) -> ValidationResult

Validate calibration data using the default validator.

Source code in src/qubitos/validation/__init__.py
def validate_calibration(
    t1_us: float,
    t2_us: float,
    readout_fidelity: float | None = None,
    gate_fidelity: float | None = None,
) -> ValidationResult:
    """Validate calibration data using the default validator."""
    return default_validator.validate_calibration(t1_us, t2_us, readout_fidelity, gate_fidelity)

AgentBible Integration

qubitos.validation.is_agentbible_available

is_agentbible_available() -> bool

Check if AgentBible is installed and available.

Source code in src/qubitos/validation/__init__.py
def is_agentbible_available() -> bool:
    """Check if AgentBible is installed and available."""
    return _agentbible_available

qubitos.validation.AgentBibleValidator

AgentBibleValidator()

Wrapper for AgentBible validation functionality.

This class provides a consistent interface to AgentBible validators, with graceful fallback when AgentBible is not installed.

Usage

validator = AgentBibleValidator()

Validate Hamiltonian

result = validator.validate_hamiltonian(hamiltonian_matrix) if not result.valid: print(f"Errors: {result.errors}")

Validate with provenance tracking

with validator.provenance_context(seed=42) as ctx: pulse = optimize_pulse(...) ctx.attach_metadata({"fidelity": pulse.fidelity})

Source code in src/qubitos/validation/__init__.py
def __init__(self) -> None:
    self._ab_available = is_agentbible_available()
    if not self._ab_available:
        logger.warning(
            f"AgentBible not available: {_agentbible_import_error}. Using fallback validators."
        )

available property

available: bool

Whether AgentBible is available.

validate_hamiltonian

validate_hamiltonian(
    matrix: ndarray, tolerance: float = 1e-10
) -> ValidationResult

Validate a Hamiltonian matrix.

Checks: - Hermiticity - Dimension consistency - Spectrum bounds (if AgentBible available)

Source code in src/qubitos/validation/__init__.py
def validate_hamiltonian(
    self, matrix: np.ndarray, tolerance: float = 1e-10
) -> ValidationResult:
    """Validate a Hamiltonian matrix.

    Checks:
    - Hermiticity
    - Dimension consistency
    - Spectrum bounds (if AgentBible available)
    """
    # Always run our basic validation
    result = validate_hermitian(matrix, tolerance, name="Hamiltonian")

    if self._ab_available:
        # TODO: Call AgentBible's quantum domain validator
        # This would look something like:
        # from agentbible.domains.quantum import HamiltonianValidator
        # ab_result = HamiltonianValidator().validate(matrix)
        # result.warnings.extend(ab_result.warnings)
        pass

    return result

validate_pulse

validate_pulse(
    i_envelope: ndarray,
    q_envelope: ndarray,
    max_amplitude: float,
    num_time_steps: int,
) -> ValidationResult

Validate pulse envelopes.

Checks: - Length consistency - Amplitude bounds - NaN/Inf detection - Smoothness (if AgentBible available)

Source code in src/qubitos/validation/__init__.py
def validate_pulse(
    self,
    i_envelope: np.ndarray,
    q_envelope: np.ndarray,
    max_amplitude: float,
    num_time_steps: int,
) -> ValidationResult:
    """Validate pulse envelopes.

    Checks:
    - Length consistency
    - Amplitude bounds
    - NaN/Inf detection
    - Smoothness (if AgentBible available)
    """
    errors = []
    warnings = []

    # Validate I envelope
    i_result = validate_pulse_envelope(i_envelope, max_amplitude, num_time_steps, "I envelope")
    errors.extend(i_result.errors)
    warnings.extend(i_result.warnings)

    # Validate Q envelope
    q_result = validate_pulse_envelope(q_envelope, max_amplitude, num_time_steps, "Q envelope")
    errors.extend(q_result.errors)
    warnings.extend(q_result.warnings)

    if self._ab_available:
        # TODO: Call AgentBible's pulse validator for smoothness checks
        pass

    return ValidationResult(len(errors) == 0, errors, warnings)

validate_calibration

validate_calibration(
    t1_us: float,
    t2_us: float,
    readout_fidelity: float | None = None,
    gate_fidelity: float | None = None,
) -> ValidationResult

Validate calibration data.

Checks: - T1/T2 physics constraints - Fidelity ranges - Consistency (if AgentBible available)

Source code in src/qubitos/validation/__init__.py
def validate_calibration(
    self,
    t1_us: float,
    t2_us: float,
    readout_fidelity: float | None = None,
    gate_fidelity: float | None = None,
) -> ValidationResult:
    """Validate calibration data.

    Checks:
    - T1/T2 physics constraints
    - Fidelity ranges
    - Consistency (if AgentBible available)
    """
    errors = []
    warnings = []

    # T1/T2 validation
    t_result = validate_calibration_t1_t2(t1_us, t2_us)
    errors.extend(t_result.errors)
    warnings.extend(t_result.warnings)

    # Fidelity validation
    if readout_fidelity is not None:
        f_result = validate_fidelity(readout_fidelity, "readout_fidelity")
        errors.extend(f_result.errors)
        warnings.extend(f_result.warnings)

    if gate_fidelity is not None:
        f_result = validate_fidelity(gate_fidelity, "gate_fidelity")
        errors.extend(f_result.errors)
        warnings.extend(f_result.warnings)

    if self._ab_available:
        # TODO: Call AgentBible's calibration validator
        pass

    return ValidationResult(len(errors) == 0, errors, warnings)