Files
rUv 407b46b206 feat: vendor midstream and sublinear-time-solver libraries (#109)
Add ruvnet/midstream (AIMDS real-time inference) and
ruvnet/sublinear-time-solver (sublinear optimization algorithms)
as vendored dependencies under vendor/.
2026-03-02 23:34:05 -05:00

351 lines
10 KiB
Rust

//! Highly optimized temporal neural solver
//! Target: <10µs P99.9 latency
use std::arch::x86_64::*;
use std::alloc::{alloc, dealloc, Layout};
use std::time::{Duration, Instant};
/// SIMD-optimized neural network with pre-allocated memory
pub struct OptimizedNeuralNetwork {
// Flattened weight matrices for cache efficiency
w1_flat: *mut f32, // 32x128 = 4096 elements
w2_flat: *mut f32, // 4x32 = 128 elements
b1: [f32; 32],
b2: [f32; 4],
// Pre-allocated buffers
hidden_buffer: [f32; 32],
// Dimensions for safety
w1_rows: usize,
w1_cols: usize,
w2_rows: usize,
w2_cols: usize,
}
impl OptimizedNeuralNetwork {
pub fn new() -> Self {
unsafe {
// Allocate aligned memory for SIMD
let w1_layout = Layout::from_size_align(4096 * 4, 32).unwrap();
let w2_layout = Layout::from_size_align(128 * 4, 32).unwrap();
let w1_ptr = alloc(w1_layout) as *mut f32;
let w2_ptr = alloc(w2_layout) as *mut f32;
// Initialize weights
for i in 0..4096 {
*w1_ptr.add(i) = ((i as f32) * 0.001).sin() * 0.1;
}
for i in 0..128 {
*w2_ptr.add(i) = ((i as f32) * 0.002).cos() * 0.2;
}
Self {
w1_flat: w1_ptr,
w2_flat: w2_ptr,
b1: [0.0; 32],
b2: [0.0; 4],
hidden_buffer: [0.0; 32],
w1_rows: 32,
w1_cols: 128,
w2_rows: 4,
w2_cols: 32,
}
}
}
#[inline(always)]
pub unsafe fn forward_simd(&mut self, input: &[f32; 128]) -> [f32; 4] {
// Layer 1: Matrix multiplication with AVX2
for i in 0..self.w1_rows {
let mut sum = _mm256_setzero_ps();
// Process 8 elements at a time with AVX2
for j in (0..self.w1_cols).step_by(8) {
let w = _mm256_loadu_ps(self.w1_flat.add(i * self.w1_cols + j));
let x = _mm256_loadu_ps(input.as_ptr().add(j));
sum = _mm256_fmadd_ps(w, x, sum);
}
// Sum the 8 floats in the AVX register
let sum_array = std::mem::transmute::<__m256, [f32; 8]>(sum);
let mut total = self.b1[i];
for k in 0..8 {
total += sum_array[k];
}
// ReLU activation
self.hidden_buffer[i] = total.max(0.0);
}
// Layer 2: Small matrix, unroll manually
let mut output = [0.0f32; 4];
// Fully unrolled for 4x32
for i in 0..4 {
let mut sum = self.b2[i];
// Unroll groups of 4
for j in (0..32).step_by(4) {
sum += *self.w2_flat.add(i * 32 + j) * self.hidden_buffer[j]
+ *self.w2_flat.add(i * 32 + j + 1) * self.hidden_buffer[j + 1]
+ *self.w2_flat.add(i * 32 + j + 2) * self.hidden_buffer[j + 2]
+ *self.w2_flat.add(i * 32 + j + 3) * self.hidden_buffer[j + 3];
}
output[i] = sum;
}
output
}
}
impl Drop for OptimizedNeuralNetwork {
fn drop(&mut self) {
unsafe {
let w1_layout = Layout::from_size_align(4096 * 4, 32).unwrap();
let w2_layout = Layout::from_size_align(128 * 4, 32).unwrap();
dealloc(self.w1_flat as *mut u8, w1_layout);
dealloc(self.w2_flat as *mut u8, w2_layout);
}
}
}
/// Optimized Kalman filter with static arrays
pub struct OptimizedKalmanFilter {
state: [f64; 8], // 4 positions + 4 velocities
diagonal_cov: [f64; 8], // Only store diagonal for speed
process_noise: f64,
measurement_noise: f64,
}
impl OptimizedKalmanFilter {
pub fn new() -> Self {
Self {
state: [0.0; 8],
diagonal_cov: [0.1; 8],
process_noise: 0.001,
measurement_noise: 0.01,
}
}
#[inline(always)]
pub fn predict_fast(&mut self, dt: f64) -> [f32; 4] {
// Unrolled position update
self.state[0] += self.state[4] * dt;
self.state[1] += self.state[5] * dt;
self.state[2] += self.state[6] * dt;
self.state[3] += self.state[7] * dt;
// Update covariance diagonal
for i in 0..8 {
self.diagonal_cov[i] += self.process_noise;
}
// Return positions as f32
[
self.state[0] as f32,
self.state[1] as f32,
self.state[2] as f32,
self.state[3] as f32,
]
}
#[inline(always)]
pub fn update_fast(&mut self, measurement: &[f32; 4]) {
// Simplified diagonal Kalman update
for i in 0..4 {
let error = measurement[i] as f64 - self.state[i];
let gain = self.diagonal_cov[i] / (self.diagonal_cov[i] + self.measurement_noise);
self.state[i] += gain * error;
self.diagonal_cov[i] *= 1.0 - gain;
}
}
}
/// Ultra-fast solver using precomputed LU decomposition
pub struct OptimizedSolver {
// Pre-allocated workspace
workspace: [f64; 16],
max_iterations: usize,
}
impl OptimizedSolver {
pub fn new() -> Self {
Self {
workspace: [0.0; 16],
max_iterations: 10, // Reduced iterations for speed
}
}
#[inline(always)]
pub fn solve_fast(&mut self, jacobian: &[[f32; 4]; 4], b: &[f32; 4]) -> (f64, usize) {
// Initialize with b
for i in 0..4 {
self.workspace[i] = b[i] as f64;
}
// Gauss-Seidel iteration (faster convergence than Jacobi)
let mut residual_norm = 0.0;
let mut iterations = 0;
for iter in 0..self.max_iterations {
residual_norm = 0.0;
// Unrolled Gauss-Seidel update
for i in 0..4 {
let mut sum = b[i] as f64;
// Use updated values immediately
for j in 0..4 {
if i != j {
sum -= jacobian[i][j] as f64 * self.workspace[j];
}
}
let diag = jacobian[i][i] as f64;
if diag.abs() > 1e-10 {
let new_val = sum / diag;
let diff = new_val - self.workspace[i];
residual_norm += diff * diff;
self.workspace[i] = new_val;
}
}
iterations = iter + 1;
if residual_norm < 1e-12 {
break;
}
}
(residual_norm.sqrt(), iterations)
}
}
/// Complete optimized temporal solver
pub struct UltraFastTemporalSolver {
nn: OptimizedNeuralNetwork,
kalman: OptimizedKalmanFilter,
solver: OptimizedSolver,
// Pre-allocated buffers
jacobian_buffer: [[f32; 4]; 4],
prediction_buffer: [f32; 4],
}
impl UltraFastTemporalSolver {
pub fn new() -> Self {
Self {
nn: OptimizedNeuralNetwork::new(),
kalman: OptimizedKalmanFilter::new(),
solver: OptimizedSolver::new(),
jacobian_buffer: [[0.0; 4]; 4],
prediction_buffer: [0.0; 4],
}
}
#[inline(always)]
pub fn predict_optimized(&mut self, input: &[f32; 128]) -> ([f32; 4], Duration) {
let start = Instant::now();
unsafe {
// 1. Kalman prediction (optimized)
let prior = self.kalman.predict_fast(0.001);
// 2. Neural network (SIMD optimized)
let residual = self.nn.forward_simd(input);
// 3. Combine (vectorized)
for i in 0..4 {
self.prediction_buffer[i] = prior[i] + residual[i];
}
// 4. Simplified Jacobian (identity + small perturbation)
for i in 0..4 {
for j in 0..4 {
self.jacobian_buffer[i][j] = if i == j { 1.0 } else { 0.01 };
}
}
// 5. Fast solver
let (_residual, _iters) = self.solver.solve_fast(&self.jacobian_buffer, &self.prediction_buffer);
// 6. Fast Kalman update
self.kalman.update_fast(&self.prediction_buffer);
}
(self.prediction_buffer, start.elapsed())
}
}
/// Batch processing for even better throughput
pub struct BatchProcessor {
solver: UltraFastTemporalSolver,
}
impl BatchProcessor {
pub fn new() -> Self {
Self {
solver: UltraFastTemporalSolver::new(),
}
}
/// Process multiple inputs with cache-friendly access
pub fn process_batch(&mut self, inputs: &[[f32; 128]], batch_size: usize) -> Vec<([f32; 4], Duration)> {
let mut results = Vec::with_capacity(batch_size);
// Prefetch next input while processing current
for i in 0..batch_size.min(inputs.len()) {
// Prefetch next data
if i + 1 < inputs.len() {
unsafe {
_mm_prefetch(inputs[i + 1].as_ptr() as *const i8, _MM_HINT_T0);
}
}
let result = self.solver.predict_optimized(&inputs[i]);
results.push(result);
}
results
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_optimized_performance() {
let mut solver = UltraFastTemporalSolver::new();
let input = [0.1f32; 128];
// Warmup
for _ in 0..1000 {
let _ = solver.predict_optimized(&input);
}
// Benchmark
let mut timings = Vec::new();
for _ in 0..1000 {
let (_pred, duration) = solver.predict_optimized(&input);
timings.push(duration);
}
timings.sort();
let p50 = timings[500];
let p99 = timings[990];
let p999 = timings[999];
println!("Optimized Performance:");
println!(" P50: {:?}", p50);
println!(" P99: {:?}", p99);
println!(" P99.9: {:?}", p999);
assert!(p999.as_micros() < 50); // Should be under 50µs
}
}
// Remove the unnecessary self:: prefix and unused imports