Files
wifi-densepose/vendor/ruvector/crates/ruvector-delta-wasm/src/apply.rs

234 lines
6.4 KiB
Rust

//! Delta application optimizations
//!
//! Provides optimized routines for applying deltas to vectors.
use ruvector_delta_core::{Delta, DeltaValue, VectorDelta};
/// Apply delta to a vector in-place
pub fn apply_delta(base: &mut [f32], delta: &VectorDelta) -> Result<(), &'static str> {
if base.len() != delta.dimensions {
return Err("Dimension mismatch");
}
match &delta.value {
DeltaValue::Identity => {
// No change
}
DeltaValue::Sparse(ops) => {
for op in ops {
let idx = op.index as usize;
if idx < base.len() {
base[idx] += op.value;
}
}
}
DeltaValue::Dense(deltas) => {
apply_dense(base, deltas);
}
DeltaValue::Replace(new_values) => {
base.copy_from_slice(new_values);
}
}
Ok(())
}
/// Optimized dense application
fn apply_dense(base: &mut [f32], deltas: &[f32]) {
// Process in chunks of 8 for better CPU utilization
let chunks = base.len() / 8;
let remainder = base.len() % 8;
for i in 0..chunks {
let offset = i * 8;
base[offset] += deltas[offset];
base[offset + 1] += deltas[offset + 1];
base[offset + 2] += deltas[offset + 2];
base[offset + 3] += deltas[offset + 3];
base[offset + 4] += deltas[offset + 4];
base[offset + 5] += deltas[offset + 5];
base[offset + 6] += deltas[offset + 6];
base[offset + 7] += deltas[offset + 7];
}
let start = chunks * 8;
for i in 0..remainder {
base[start + i] += deltas[start + i];
}
}
/// SIMD-accelerated delta application
#[cfg(target_feature = "simd128")]
pub fn apply_delta_simd(base: &mut [f32], delta: &VectorDelta) -> Result<(), &'static str> {
use core::arch::wasm32::*;
if base.len() != delta.dimensions {
return Err("Dimension mismatch");
}
match &delta.value {
DeltaValue::Identity => Ok(()),
DeltaValue::Sparse(ops) => {
for op in ops {
let idx = op.index as usize;
if idx < base.len() {
base[idx] += op.value;
}
}
Ok(())
}
DeltaValue::Dense(deltas) => {
let chunks = base.len() / 4;
for i in 0..chunks {
let offset = i * 4;
unsafe {
let base_ptr = base.as_mut_ptr().add(offset);
let delta_ptr = deltas.as_ptr().add(offset);
let base_vec = v128_load(base_ptr as *const v128);
let delta_vec = v128_load(delta_ptr as *const v128);
let result = f32x4_add(base_vec, delta_vec);
v128_store(base_ptr as *mut v128, result);
}
}
// Handle remainder
for i in (chunks * 4)..base.len() {
base[i] += deltas[i];
}
Ok(())
}
DeltaValue::Replace(new_values) => {
base.copy_from_slice(new_values);
Ok(())
}
}
}
/// Apply delta with scaling factor
pub fn apply_scaled(base: &mut [f32], delta: &VectorDelta, scale: f32) -> Result<(), &'static str> {
if base.len() != delta.dimensions {
return Err("Dimension mismatch");
}
match &delta.value {
DeltaValue::Identity => {
// No change
}
DeltaValue::Sparse(ops) => {
for op in ops {
let idx = op.index as usize;
if idx < base.len() {
base[idx] += op.value * scale;
}
}
}
DeltaValue::Dense(deltas) => {
for (b, d) in base.iter_mut().zip(deltas.iter()) {
*b += d * scale;
}
}
DeltaValue::Replace(new_values) => {
// For replace, scale interpolates between old and new
for (b, n) in base.iter_mut().zip(new_values.iter()) {
*b = *b * (1.0 - scale) + *n * scale;
}
}
}
Ok(())
}
/// Batch apply to multiple vectors
pub fn apply_batch(bases: &mut [&mut [f32]], delta: &VectorDelta) -> Result<(), &'static str> {
for base in bases {
apply_delta(*base, delta)?;
}
Ok(())
}
/// Apply multiple deltas to a single vector
pub fn apply_sequence(base: &mut [f32], deltas: &[VectorDelta]) -> Result<(), &'static str> {
for delta in deltas {
apply_delta(base, delta)?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use ruvector_delta_core::Delta;
#[test]
fn test_apply_sparse() {
let old = vec![1.0f32, 2.0, 3.0, 4.0, 5.0];
let new = vec![1.0f32, 2.5, 3.0, 4.5, 5.0];
let delta = VectorDelta::compute(&old, &new);
let mut result = old.clone();
apply_delta(&mut result, &delta).unwrap();
for (r, n) in result.iter().zip(new.iter()) {
assert!((r - n).abs() < 1e-6);
}
}
#[test]
fn test_apply_dense() {
let old = vec![1.0f32, 2.0, 3.0];
let new = vec![2.0f32, 3.0, 4.0];
let delta = VectorDelta::compute(&old, &new);
let mut result = old.clone();
apply_delta(&mut result, &delta).unwrap();
for (r, n) in result.iter().zip(new.iter()) {
assert!((r - n).abs() < 1e-6);
}
}
#[test]
fn test_apply_scaled() {
let mut base = vec![0.0f32, 0.0, 0.0];
let delta = VectorDelta::from_dense(vec![1.0, 2.0, 3.0]);
apply_scaled(&mut base, &delta, 0.5).unwrap();
assert!((base[0] - 0.5).abs() < 1e-6);
assert!((base[1] - 1.0).abs() < 1e-6);
assert!((base[2] - 1.5).abs() < 1e-6);
}
#[test]
fn test_apply_sequence() {
let mut base = vec![0.0f32, 0.0, 0.0];
let deltas = vec![
VectorDelta::from_dense(vec![1.0, 0.0, 0.0]),
VectorDelta::from_dense(vec![0.0, 1.0, 0.0]),
VectorDelta::from_dense(vec![0.0, 0.0, 1.0]),
];
apply_sequence(&mut base, &deltas).unwrap();
assert!((base[0] - 1.0).abs() < 1e-6);
assert!((base[1] - 1.0).abs() < 1e-6);
assert!((base[2] - 1.0).abs() < 1e-6);
}
#[test]
fn test_dimension_mismatch() {
let mut base = vec![0.0f32; 5];
let delta = VectorDelta::new(10); // Different dimensions
let result = apply_delta(&mut base, &delta);
assert!(result.is_err());
}
}