Skip to main content

trueno/brick/
types.rs

1#![allow(missing_docs)]
2//! Core types for the ComputeBrick system.
3//!
4//! Defines execution backends, error types, assertions, and verification results.
5
6use crate::error::TruenoError;
7use std::fmt;
8
9/// Execution backend for compute operations.
10/// This is the brick-specific backend enum with additional GPU backends.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
12pub enum ComputeBackend {
13    /// Pure Rust scalar fallback (always available, baseline for correctness)
14    Scalar,
15    /// SSE2 SIMD (x86_64 baseline)
16    Sse2,
17    /// AVX2 256-bit SIMD with FMA
18    #[default]
19    Avx2,
20    /// AVX-512 512-bit SIMD
21    Avx512,
22    /// ARM NEON SIMD
23    Neon,
24    /// WebAssembly SIMD128
25    Wasm,
26    /// NVIDIA CUDA via PTX
27    Cuda,
28    /// Cross-platform GPU via wgpu
29    Wgpu,
30    /// Auto-select best available backend
31    Auto,
32}
33
34impl fmt::Display for ComputeBackend {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        match self {
37            ComputeBackend::Scalar => write!(f, "Scalar"),
38            ComputeBackend::Sse2 => write!(f, "SSE2"),
39            ComputeBackend::Avx2 => write!(f, "AVX2"),
40            ComputeBackend::Avx512 => write!(f, "AVX-512"),
41            ComputeBackend::Neon => write!(f, "NEON"),
42            ComputeBackend::Wasm => write!(f, "WASM"),
43            ComputeBackend::Cuda => write!(f, "CUDA"),
44            ComputeBackend::Wgpu => write!(f, "wgpu"),
45            ComputeBackend::Auto => write!(f, "Auto"),
46        }
47    }
48}
49
50/// Type alias for backward compatibility
51pub type Backend = ComputeBackend;
52
53/// Errors from ComputeBrick execution.
54/// Tells you exactly what failed (Jidoka: stop and signal).
55#[derive(Debug, thiserror::Error)]
56pub enum BrickError {
57    /// Assertion failed during verification
58    #[error("Assertion failed: {name} - expected {expected}, got {actual}")]
59    AssertionFailed { name: String, expected: String, actual: String },
60
61    /// Performance budget exceeded
62    #[error("Budget exceeded: {limit_us:.1}µs/tok limit, {actual_us:.1}µs/tok actual ({utilization:.0}% of budget)")]
63    BudgetExceeded { limit_us: f64, actual_us: f64, utilization: f64 },
64
65    /// Underlying compute error
66    #[error("Compute error: {0}")]
67    ComputeError(#[from] TruenoError),
68
69    /// No assertions defined (violates Popperian falsifiability)
70    #[error("Brick has no assertions - violates Popperian falsifiability requirement")]
71    NoAssertions,
72
73    /// Backend not available
74    #[error("Backend {0} not available on this system")]
75    BackendUnavailable(Backend),
76}
77
78/// Type of assertion for compute verification.
79#[derive(Debug, Clone)]
80pub enum ComputeAssertion {
81    /// Output must match baseline backend within tolerance
82    Equivalence { baseline: Backend, tolerance: f64 },
83    /// Output values must be within bounds
84    Bounds { min: f64, max: f64 },
85    /// Output must not contain NaN or infinity
86    Finite,
87    /// Custom assertion with name and check function index
88    Custom { name: String },
89}
90
91impl ComputeAssertion {
92    /// Create equivalence assertion with default tolerance (1e-5).
93    pub fn equiv(baseline: Backend) -> Self {
94        Self::Equivalence { baseline, tolerance: 1e-5 }
95    }
96
97    /// Create equivalence assertion with custom tolerance.
98    pub fn equiv_with_tolerance(baseline: Backend, tolerance: f64) -> Self {
99        Self::Equivalence { baseline, tolerance }
100    }
101
102    /// Create bounds assertion.
103    pub fn bounds(min: f64, max: f64) -> Self {
104        contract_pre_bounds!();
105        Self::Bounds { min, max }
106    }
107
108    /// Create finite assertion (no NaN/Inf).
109    pub fn finite() -> Self {
110        Self::Finite
111    }
112}
113
114/// Verification result from ComputeBrick.
115#[derive(Debug, Clone)]
116pub struct BrickVerification {
117    /// Overall pass/fail
118    pub passed: bool,
119    /// Individual assertion results
120    pub assertion_results: Vec<AssertionResult>,
121    /// Verification time in microseconds
122    pub verification_us: f64,
123}
124
125impl BrickVerification {
126    /// Check if all assertions passed.
127    pub fn is_valid(&self) -> bool {
128        self.passed
129    }
130
131    /// Get failed assertions.
132    pub fn failures(&self) -> impl Iterator<Item = &AssertionResult> {
133        self.assertion_results.iter().filter(|r| !r.passed)
134    }
135}
136
137/// Result of a single assertion check.
138#[derive(Debug, Clone)]
139pub struct AssertionResult {
140    /// Assertion that was checked
141    pub assertion: ComputeAssertion,
142    /// Did it pass?
143    pub passed: bool,
144    /// Error message if failed
145    pub error: Option<String>,
146}
147
148/// Trait for compute operations that can be wrapped in a ComputeBrick.
149pub trait ComputeOp: Send + Sync {
150    /// Input type for this operation
151    type Input;
152    /// Output type for this operation
153    type Output;
154
155    /// Operation name for identification
156    fn name(&self) -> &'static str;
157
158    /// Execute the operation on the given backend
159    fn execute(&self, input: Self::Input, backend: Backend) -> Result<Self::Output, TruenoError>;
160
161    /// Number of tokens this operation processes (for budget calculation)
162    fn tokens(&self, input: &Self::Input) -> usize;
163
164    /// Clone the input for verification (if needed)
165    fn clone_input(&self, input: &Self::Input) -> Option<Self::Input>
166    where
167        Self::Input: Clone,
168    {
169        Some(input.clone())
170    }
171}