Slices dot product in std lib?


#1

I’ve submitted an improved version of the mat_mul benchmark here:

Later I’ve written a faster version:

// Compile with: rustc -C opt-level=3 -C target-cpu=native

fn mat_gen(n: usize) -> Vec<Vec<f64>> {
    let mut m = vec![vec![0.0; n]; n];
    let k = 1.0 / (n as f64) / (n as f64);

    for i in 0 .. n {
        for j in 0 .. n {
            m[i][j] = k * (i as f64 - j as f64) * (i as f64 + j as f64);
        }
    }
    m
}

#[inline(never)]
fn dot_product(a: &[f64], b: &[f64]) -> f64 {
    debug_assert_eq!(a.len(), b.len());
    let size = a.len() as isize;
    let mut ap = a.as_ptr();
    let mut bp = b.as_ptr();
    let mut tot = [0.0, 0.0];

    unsafe {
        let end_ptr = ap.offset(size);
        const BLOCK_SIZE: isize = 16;
        let block_end_ptr = ap.offset(size & !(BLOCK_SIZE - 1));

        while ap != block_end_ptr {
            for i in 0 .. BLOCK_SIZE {
                tot[i as usize % 2] += *ap.offset(i) * *bp.offset(i);
            }
            ap = ap.offset(BLOCK_SIZE);
            bp = bp.offset(BLOCK_SIZE);
        }

        tot[0] += tot[1];

        while ap != end_ptr {
            tot[0] += *ap * *bp;
            ap = ap.offset(1);
            bp = bp.offset(1);
        }
    }

    tot[0]
}

fn mat_mul(a: &[Vec<f64>], b: &[Vec<f64>]) -> Vec<Vec<f64>> {
    let m = a.len();
    let n = a[0].len();
    let p = b[0].len();

    let mut c = vec![vec![0.0; p]; n];
    for (i, b_row) in b.iter().enumerate() {
        for (j, b_el) in b_row.iter().enumerate() {
            c[j][i] = *b_el;
        }
    }

    let mut res = vec![vec![0.0; p]; m];
    for (i, a_row) in a.iter().enumerate() {
        for (res_ij, c_row) in res[i].iter_mut().zip(&c) {
            *res_ij = dot_product(a_row, c_row);
        }
    }

    res
}

fn main() {
    let n = std::env::args()
            .nth(1)
            .unwrap_or("1500".into())
            .parse::<usize>()
            .unwrap() / 2 * 2;

    let a = mat_gen(n);
    let b = mat_gen(n);
    let c = mat_mul(&a, &b);
    println!("{}", c[n / 2][n / 2]);
}

With those rustc compilation switches LLLV is able to turn that dot_product() into quite efficient asm code (the inline(never) is useful here but I don’t know why).

In the D standard library there is a dotProduct() function ( https://dlang.org/library/std/numeric/dot_product.html ). Is it a good idea to add to the Rust std lib a slice method s1.dot_product(s2) similar to the one I’ve written above, with small changes (it returns None if the two slices have a different lenght. T has AddAssign or Add, Mul and a zero)?

fn dot_product(&self, other: &[T]) -> Option<T>;


#2

I have the impression that they’re is always a sort of mix between different semantical domains when speaking about “vectors”. To me it is unfortunate that Rust followed C++ by choosing the word vector for a resizable arrays. So with the same kind of arguments I don’t understand why a concept of linear algebra (the dot product) should be related to arrays (even float arrays). Why isn’t a separate lib dedicated to linear algebra sufficient?