1#![allow(missing_docs)]
2use crate::error::TruenoError;
7use std::fmt;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
12pub enum ComputeBackend {
13 Scalar,
15 Sse2,
17 #[default]
19 Avx2,
20 Avx512,
22 Neon,
24 Wasm,
26 Cuda,
28 Wgpu,
30 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
50pub type Backend = ComputeBackend;
52
53#[derive(Debug, thiserror::Error)]
56pub enum BrickError {
57 #[error("Assertion failed: {name} - expected {expected}, got {actual}")]
59 AssertionFailed { name: String, expected: String, actual: String },
60
61 #[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 #[error("Compute error: {0}")]
67 ComputeError(#[from] TruenoError),
68
69 #[error("Brick has no assertions - violates Popperian falsifiability requirement")]
71 NoAssertions,
72
73 #[error("Backend {0} not available on this system")]
75 BackendUnavailable(Backend),
76}
77
78#[derive(Debug, Clone)]
80pub enum ComputeAssertion {
81 Equivalence { baseline: Backend, tolerance: f64 },
83 Bounds { min: f64, max: f64 },
85 Finite,
87 Custom { name: String },
89}
90
91impl ComputeAssertion {
92 pub fn equiv(baseline: Backend) -> Self {
94 Self::Equivalence { baseline, tolerance: 1e-5 }
95 }
96
97 pub fn equiv_with_tolerance(baseline: Backend, tolerance: f64) -> Self {
99 Self::Equivalence { baseline, tolerance }
100 }
101
102 pub fn bounds(min: f64, max: f64) -> Self {
104 contract_pre_bounds!();
105 Self::Bounds { min, max }
106 }
107
108 pub fn finite() -> Self {
110 Self::Finite
111 }
112}
113
114#[derive(Debug, Clone)]
116pub struct BrickVerification {
117 pub passed: bool,
119 pub assertion_results: Vec<AssertionResult>,
121 pub verification_us: f64,
123}
124
125impl BrickVerification {
126 pub fn is_valid(&self) -> bool {
128 self.passed
129 }
130
131 pub fn failures(&self) -> impl Iterator<Item = &AssertionResult> {
133 self.assertion_results.iter().filter(|r| !r.passed)
134 }
135}
136
137#[derive(Debug, Clone)]
139pub struct AssertionResult {
140 pub assertion: ComputeAssertion,
142 pub passed: bool,
144 pub error: Option<String>,
146}
147
148pub trait ComputeOp: Send + Sync {
150 type Input;
152 type Output;
154
155 fn name(&self) -> &'static str;
157
158 fn execute(&self, input: Self::Input, backend: Backend) -> Result<Self::Output, TruenoError>;
160
161 fn tokens(&self, input: &Self::Input) -> usize;
163
164 fn clone_input(&self, input: &Self::Input) -> Option<Self::Input>
166 where
167 Self::Input: Clone,
168 {
169 Some(input.clone())
170 }
171}