vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
//! Comparators for GPU/CPU output parity checking.
//!
//! Three strategies are provided:
//! - [`ExactMatch`] — byte-for-byte identity (default).
//! - [`UnorderedMatch`] — inferred typed-element set equality.
//! - [`ApproximateMatch`] — ULP tolerance for floating-point output words.

mod strategies;
mod validate;

pub use crate::spec::types::ComparatorKind;
pub use validate::validate_comparator_for_type;

/// Compares backend output against the CPU reference output.
pub trait Comparator: Send + Sync {
    /// Compare GPU output against CPU reference.
    ///
    /// Returns `Ok(())` on match, `Err(message)` with diagnostic details on mismatch.
    fn compare(&self, gpu: &[u8], cpu: &[u8]) -> Result<(), String>;
}

/// Byte-for-byte exact comparator with word-level diagnostics.
pub struct ExactMatch;

/// Set-equality comparator using inferred typed element width.
pub struct UnorderedMatch;

/// ULP tolerance comparator.
pub struct ApproximateMatch {
    /// Maximum acceptable ULP distance per output element.
    pub epsilon: u32,
}

/// Structured set-equality comparator.
pub struct SetEqualityMatch {
    /// Byte size of each element.
    pub element_size: usize,
}

impl ComparatorKind {
    /// Dispatch comparison to the appropriate strategy.
    #[inline]
    pub fn compare(self, gpu: &[u8], cpu: &[u8]) -> Result<(), String> {
        match self {
            Self::ExactMatch => ExactMatch.compare(gpu, cpu),
            Self::UnorderedMatch => UnorderedMatch.compare(gpu, cpu),
            Self::Approximate { epsilon } => ApproximateMatch { epsilon }.compare(gpu, cpu),
            Self::SetEquality { element_size } => {
                SetEqualityMatch { element_size }.compare(gpu, cpu)
            }
        }
    }
}

/// Forward `&ComparatorKind` to the `Comparator` trait so generic callers
/// (e.g., the proptest_comparator_symmetry integration test) can treat any
/// kind uniformly with the strategy structs.
impl Comparator for ComparatorKind {
    fn compare(&self, gpu: &[u8], cpu: &[u8]) -> Result<(), String> {
        (*self).compare(gpu, cpu)
    }
}

#[cfg(test)]
mod tests;