Core Concepts
Understanding Trueno's fundamental concepts will help you write efficient, safe code.
The Vector Type
Vector<T> is Trueno's core abstraction:
use trueno::Vector;
let v = Vector::from_slice(&[1.0, 2.0, 3.0, 4.0]);
Key properties:
- Generic over numeric types:
f32,f64,i32,i64 - Immutable by default (functional style)
- Backend selected at creation time (no repeated detection)
- Zero-copy views with
as_slice()
Backend Selection
Trueno automatically selects the best backend when you create a Vector:
// Automatic backend selection
let v = Vector::from_slice(&[1.0; 1000]);
println!("{:?}", v.backend()); // Avx2, Sse2, Neon, etc.
// Manual backend override (for testing/profiling)
let v = Vector::with_backend(&[1.0; 1000], Backend::Scalar);
Selection priority:
- GPU (if workload >100K elements and GPU available)
- AVX-512 (if CPU supports)
- AVX2 (if CPU supports)
- AVX (if CPU supports)
- SSE2 (x86_64 baseline)
- NEON (ARM64)
- Scalar fallback
Safety Model
Trueno maintains safety through three layers:
Layer 1: Type System
// Compile-time type safety
let a = Vector::from_slice(&[1.0f32, 2.0, 3.0]);
let b = Vector::from_slice(&[4.0f64, 5.0, 6.0]);
// ❌ Compile error: type mismatch
// let result = a.add(&b);
Layer 2: Runtime Validation
// Runtime size checking
let a = Vector::from_slice(&[1.0, 2.0, 3.0]);
let b = Vector::from_slice(&[4.0, 5.0]);
// Returns Err(SizeMismatch)
let result = a.add(&b);
Layer 3: Unsafe Isolation
All unsafe code is isolated to backend implementations:
// ✅ 100% safe public API
pub fn add(&self, other: &Self) -> Result<Self> {
validate_sizes(self, other)?; // Safe
match self.backend {
Backend::Avx2 => unsafe { self.add_avx2(other) }, // ❌ Unsafe (internal only)
Backend::Scalar => self.add_scalar(other), // ✅ Safe
}
}
Error Handling
Trueno uses Rust's Result type for robust error handling:
use trueno::{Vector, TruenoError};
fn process_vectors() -> Result<Vector, TruenoError> {
let a = Vector::from_slice(&[1.0, 2.0, 3.0]);
let b = Vector::from_slice(&[4.0, 5.0, 6.0]);
let sum = a.add(&b)?; // Propagate errors with ?
let product = sum.mul_scalar(2.0)?;
Ok(product)
}
Error types:
SizeMismatch- Vectors have incompatible sizesBackendError- Backend initialization failedGpuError- GPU operation failedInvalidInput- Invalid parameters (NaN, infinity)
Performance Model
Understanding Trueno's performance characteristics helps you write efficient code.
Operation Complexity
Operations fall into three categories:
Low complexity (add, sub, mul, div):
- Prefer SIMD for >1K elements
- Memory-bandwidth limited
- Expect 1.1-2x speedup
Medium complexity (dot, sum, max):
- SIMD shines here (3-5x speedup)
- Compute-bound, not memory-bound
- Use SIMD even for 100 elements
High complexity (tanh, exp, log):
- Excellent SIMD performance (6-9x speedup)
- Compute-intensive operations
- Consider GPU for >100K elements
Backend Overhead
Each backend has different overhead characteristics:
| Backend | Overhead | Best For |
|---|---|---|
| Scalar | None | <100 elements, testing |
| SSE2 | ~20ns | 100-100K elements |
| AVX2 | ~30ns | 1K-100K elements |
| GPU | ~0.5ms | >100K elements |
Next Steps
- First Program - Build a complete example
- Architecture Overview - Deep dive into backends
- API Reference - Explore all operations