NDArray ergonomics

I have piece of code like this (very typical update equation in algorithms like SGD):
vector += &(scalar * vector_2.dot(matrix));

Compared to similar numpy code in Python:
vector += scalar * np.dot(vector_2, matrix)

the Rust variant feels quite nonergonomic.

Thus, my question is: Is there some reason that += operator cannot consume both value and reference? Am I missing some silent optimization NDArray is doing for me?

Relevant discussion links:

https://github.com/rust-lang/rfcs/pull/2147

https://github.com/rust-lang/rust/issues/44619

1 Like

hi, do you mean the ndarray crate? The code for its += implementation is quite old, so I don't remember if there is a technical limitation there.

In parts, the ndarray crate errs on the too strict side when it comes to being explicit. The example here would be since that the += operator only needs to read from the right hand side operand, it should refuse to consume that operand. The theory is that this helps to avoid unnecessary expensive operations!

As it is now, ndarray has the tools that let you express this without intermediate arrays, but around that, there's an even more tricky question of making a nice interface for it.

Can you look into using general_mat_mul or general_mat_vec_mul to compute the matrix multiplication, scaling, and addition in one go? It's not exactly easy to use either, but in theory it does this efficiently.

There are a few more general and specific methods like .zip_mut_with or using Zip for custom array traversals that perform elementwise operations, scaled_add:.

There are other Rust crates that experiment with more convenient ways to express this, but I don't really know what they have achieved in comparison.

Note that std decided that += would be implemented on T not on &T. It was more ergonomic and all the T happened to be copy. Adding the impl was a long process, but soon you will be able to write code generic over ndarray and std numbers.

https://github.com/rust-lang/rust/pull/44287

Thanks all. It seems, that I would just have to wait till discussions around mentioned RFCs settle :slight_smile:
And also thanks to @bluss to pointing out more efficient ways of achieving things (although slightly less readable :wink: )