# Efficient ways of computing a centered gradient?

I’m trying different implementations to compute a centered gradient, so `(f(x+1) - f(x-1))/2` instead of `f(x+1)-f(x)`. Except I’m not dividing by 2 for performances reasons. To avoid complications at the boundary, I can also get rid of them, so the gradient matrix is of size `(nrows-2, ncols-2)`. I’ve tried two ways for the moment, and it appears that the `slice` way is way faster than the `from_fn` one. Are there other more idiomatic and efficient ways of computing this in Rust with nalgebra?

``````fn gradient_x_inner_from_fn(mat: &DMatrix<u8>) -> DMatrix<i16> {
let (nb_rows, nb_cols) = mat.shape();
DMatrix::from_fn(nb_rows - 2, nb_cols - 2, |r, c| {
mat[(r + 1, c + 2)] as i16 - mat[(r + 1, c)] as i16
})
}

fn gradient_x_inner_slice(mat: &DMatrix<u8>) -> DMatrix<i16> {
let (nb_rows, nb_cols) = mat.shape();
mat.slice((1, 2), (nb_rows - 2, nb_cols - 2)).zip_map(
&mat.slice((1, 0), (nb_rows - 2, nb_cols - 2)),
|x_2, x_0| x_2 as i16 - x_0 as i16,
)
}
``````

Since you need the conversion from `u8` to `i16`, the `zip_map` option is the best approach I can think of. (Without this conversion you could simply have subtracted the two slices to get the difference of course.)

2 Likes

Cool, that’s what I thought also, but since I’m still exploring and nalgebra is huuge (and awesome!) I don’t want to miss stuff.

PS: I had a friend more familiar to Rust investigate the performance issues. Turns out that `from_fn` is walking through the memory in a row-wise manner instead of column-wise. And since the memory representation is column major apparently, this has a big impact for big matrices. He did a PR here https://github.com/sebcrozet/nalgebra/pull/355.

1 Like

Thanks, that’s a good observation.