rill-core 0.5.0-beta.5

Core foundation for the Rill ecosystem — traits, math, buffers, queues, time, macros
Documentation
//! # Mathematical functions for vectors
//!
//! Implementation of mathematical functions (sin, cos, exp, ln, sqrt, etc.) for vector types.

use super::traits::{Vector, VectorTranscendental};
use crate::Transcendental;

// -----------------------------------------------------------------------------
// Slice functions
// -----------------------------------------------------------------------------

/// Element-wise sine of a slice
pub fn sin_slice<T: Transcendental, const N: usize, V>(input: &[T], output: &mut [T])
where
    V: VectorTranscendental<T, N>,
{
    assert_eq!(input.len(), output.len());

    let chunks = input.len() / N;
    let remainder = input.len() % N;

    for i in 0..chunks {
        let start = i * N;
        let vec = V::load(&input[start..start + N]);
        let result = vec.sin();
        result.store(&mut output[start..start + N]);
    }

    if remainder > 0 {
        let start = chunks * N;
        for i in 0..remainder {
            output[start + i] = input[start + i].sin();
        }
    }
}

/// Element-wise cosine of a slice
pub fn cos_slice<T: Transcendental, const N: usize, V>(input: &[T], output: &mut [T])
where
    V: VectorTranscendental<T, N>,
{
    assert_eq!(input.len(), output.len());

    let chunks = input.len() / N;
    let remainder = input.len() % N;

    for i in 0..chunks {
        let start = i * N;
        let vec = V::load(&input[start..start + N]);
        let result = vec.cos();
        result.store(&mut output[start..start + N]);
    }

    if remainder > 0 {
        let start = chunks * N;
        for i in 0..remainder {
            output[start + i] = input[start + i].cos();
        }
    }
}

/// Element-wise tangent of a slice
pub fn tan_slice<T: Transcendental, const N: usize, V>(input: &[T], output: &mut [T])
where
    V: VectorTranscendental<T, N>,
{
    assert_eq!(input.len(), output.len());

    let chunks = input.len() / N;
    let remainder = input.len() % N;

    for i in 0..chunks {
        let start = i * N;
        let vec = V::load(&input[start..start + N]);
        let result = vec.tan();
        result.store(&mut output[start..start + N]);
    }

    if remainder > 0 {
        let start = chunks * N;
        for i in 0..remainder {
            output[start + i] = input[start + i].tan();
        }
    }
}

/// Element-wise exponent of a slice
pub fn exp_slice<T: Transcendental, const N: usize, V>(input: &[T], output: &mut [T])
where
    V: VectorTranscendental<T, N>,
{
    assert_eq!(input.len(), output.len());

    let chunks = input.len() / N;
    let remainder = input.len() % N;

    for i in 0..chunks {
        let start = i * N;
        let vec = V::load(&input[start..start + N]);
        let result = vec.exp();
        result.store(&mut output[start..start + N]);
    }

    if remainder > 0 {
        let start = chunks * N;
        for i in 0..remainder {
            output[start + i] = input[start + i].exp();
        }
    }
}

/// Element-wise natural logarithm of a slice
pub fn ln_slice<T: Transcendental, const N: usize, V>(input: &[T], output: &mut [T])
where
    V: VectorTranscendental<T, N>,
{
    assert_eq!(input.len(), output.len());

    let chunks = input.len() / N;
    let remainder = input.len() % N;

    for i in 0..chunks {
        let start = i * N;
        let vec = V::load(&input[start..start + N]);
        let result = vec.ln();
        result.store(&mut output[start..start + N]);
    }

    if remainder > 0 {
        let start = chunks * N;
        for i in 0..remainder {
            output[start + i] = input[start + i].ln();
        }
    }
}

/// Element-wise square root of a slice
pub fn sqrt_slice<T: Transcendental, const N: usize, V>(input: &[T], output: &mut [T])
where
    V: VectorTranscendental<T, N>,
{
    assert_eq!(input.len(), output.len());

    let chunks = input.len() / N;
    let remainder = input.len() % N;

    for i in 0..chunks {
        let start = i * N;
        let vec = V::load(&input[start..start + N]);
        let result = vec.sqrt();
        result.store(&mut output[start..start + N]);
    }

    if remainder > 0 {
        let start = chunks * N;
        for i in 0..remainder {
            output[start + i] = input[start + i].sqrt();
        }
    }
}

/// Element-wise absolute value of a slice
pub fn abs_slice<T: Transcendental, const N: usize, V>(input: &[T], output: &mut [T])
where
    V: Vector<T, N>,
{
    assert_eq!(input.len(), output.len());

    let chunks = input.len() / N;
    let remainder = input.len() % N;

    for i in 0..chunks {
        let start = i * N;
        let vec = V::load(&input[start..start + N]);
        let result = vec.abs();
        result.store(&mut output[start..start + N]);
    }

    if remainder > 0 {
        let start = chunks * N;
        for i in 0..remainder {
            output[start + i] = input[start + i].abs();
        }
    }
}

/// Element-wise minimum of two slices
pub fn min_slice<T: Transcendental, const N: usize, V>(a: &[T], b: &[T], output: &mut [T])
where
    V: Vector<T, N>,
{
    assert_eq!(a.len(), b.len());
    assert_eq!(a.len(), output.len());

    let chunks = a.len() / N;
    let remainder = a.len() % N;

    for i in 0..chunks {
        let start = i * N;
        let a_vec = V::load(&a[start..start + N]);
        let b_vec = V::load(&b[start..start + N]);
        let result = a_vec.min(&b_vec);
        result.store(&mut output[start..start + N]);
    }

    if remainder > 0 {
        let start = chunks * N;
        for i in 0..remainder {
            output[start + i] = a[start + i].min(b[start + i]);
        }
    }
}

/// Element-wise maximum of two slices
pub fn max_slice<T: Transcendental, const N: usize, V>(a: &[T], b: &[T], output: &mut [T])
where
    V: Vector<T, N>,
{
    assert_eq!(a.len(), b.len());
    assert_eq!(a.len(), output.len());

    let chunks = a.len() / N;
    let remainder = a.len() % N;

    for i in 0..chunks {
        let start = i * N;
        let a_vec = V::load(&a[start..start + N]);
        let b_vec = V::load(&b[start..start + N]);
        let result = a_vec.max(&b_vec);
        result.store(&mut output[start..start + N]);
    }

    if remainder > 0 {
        let start = chunks * N;
        for i in 0..remainder {
            output[start + i] = a[start + i].max(b[start + i]);
        }
    }
}

/// Element-wise clamp of a slice
pub fn clamp_slice<T: Transcendental, const N: usize, V>(
    input: &[T],
    min: &[T],
    max: &[T],
    output: &mut [T],
) where
    V: Vector<T, N>,
{
    assert_eq!(input.len(), min.len());
    assert_eq!(input.len(), max.len());
    assert_eq!(input.len(), output.len());

    let chunks = input.len() / N;
    let remainder = input.len() % N;

    for i in 0..chunks {
        let start = i * N;
        let input_vec = V::load(&input[start..start + N]);
        let min_vec = V::load(&min[start..start + N]);
        let max_vec = V::load(&max[start..start + N]);
        let result = input_vec.clamp(&min_vec, &max_vec);
        result.store(&mut output[start..start + N]);
    }

    if remainder > 0 {
        let start = chunks * N;
        for i in 0..remainder {
            output[start + i] = input[start + i].clamp(min[start + i], max[start + i]);
        }
    }
}

// -----------------------------------------------------------------------------
// Tests
// -----------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use super::*;
    use crate::Transcendental;

    // Tests will be added after scalar vector implementation
}