The following Python code will repeatedly add the vector [1, 2, 3, 4] to  each row in the two-dimensional array a, starting only from the 20th row.
import numpy as np
# an array of shape (100, 4)
a = np.zeros((100, 4), dtype=np.float32)
# and this is the operation explained above
a[20:, :] += [1.0, 2.0, 3.0, 0.0]
Is there a simple equivalent of this with ndarray?
I can already do what I need with more complicated messy looking code but feel there is probably a tidy ndarray.rs equivalent.
OK so, at the risk of over complicating a question I thought might have a simple answer that I just couldn't unearth...
I am using arrays of f32 shape (n, 8) representing three vertex locations, three normal components and two texture mapping coordinates. I am merging buffers from multiple 3D objects into one for more efficient graphics rendering. Within the 8 wide array the first three values need to be scaled i.e. multiplied by &[sx, sy, sz] then rotated using a standard rz.dot(&rx.dot(&ry.dot())) function and finally have a displacement &[dx, dy, dz] added. The normals just need to be rotated. My current system involves holding data in intermediate array variables.
use ndarray as nd;
array_buffer: nd::Array2<f32>, loc: &[f32; 3], scl: &[f32; 3]...
...
// scale then rotate new verts then add displacement
let new_verts = &new_buf.array_buffer.slice(s![.., 0..3]) * &nd::arr1(scl);
let new_verts = rotate_vec(rot, &new_verts) + &nd::arr1(loc);
// then add them to existing verts
let mut verts = nd::stack(nd::Axis(0),
                &[old_buf.array_buffer.slice(s![.., 0..3]),
                  new_verts.view()]).unwrap();
...
I know I won't be able to reduce it to the numpy one liner
verts = np.append(old_buf.array_buffer[:,0:3], 
        rotate_vec(rot, (new_buf.array_buffer[:,0:3] * scl) + loc))
but I thought that maybe some of the map or zip variants or macros might help me.
That can be done with the same two steps as those performed in Python: slicing, then add-assigning to a broadcast right-handed array.
use ndarray::Array2;
let mut a: Array2<f32> = Array2::zeros((100, 4));
{ 
    let mut slice = a.slice_mut(s![20.., ..]);
    slice += &ArrayView::from(&[1.0, 2.0, 3.0, 4.0]);
}
Slicing is done with slice_mut and the s! macro for defining the intended range.
The outcome of a slice is a mutable array view, and so, most operations seen in ArrayBase are available, including arithmetic operations. 
By broadcasting rules, a right-handed array of shape [4] can be automatically broadcast to one of shape [100, 4] for the += operator.
In case of other confusions in the transition from Python to Rust's ndarray crate, the documentation contains a guide for Python users.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With