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