Creating ndarray of zeros by cutting off last dimension of an input array

Hi!
I am trying to write a function which takes an ndarray array of a general dimension Array<f64,D>, and returns an array of zeros obtained by cutting off the size of the last dimension, of type Array<f64,S> where S is one smaller than D. So, for example, if I have an input array of shape 3x5x7x2, the output would be a 3x5x7 array of zeros. I am having trouble getting the dimensionality information into the type, and should not use any unsafe functions to do this. Any help to make something like the following work would be appreciated!

pub fn create_zeros<D: Dimension<Smaller = S>, S: Dimension<Larger = D>>(
        x: &Array<f64, D>,
    ) -> Array<f64, S> {
        let (&x_last_dim, storage_shape) = x
            .shape()
            .split_last()
            .expect("Expected x to have at least one dimension!");
       
        // how would it be possible to remove the last element?
        // let t = points.raw_dim(); 
   
        // or how can I make this work?
        // let output = Array::<f64, S>::zeros(storage_shape); 
}

I'm not sure what you are trying to do with the two generic parameters, since D::Smaller is already an associated type, and dimensions are Default. So you can just create an all-zero vector and then use from_shape_vec:

fn create_zeros<T, D>(a: ArrayBase<T, D>) -> Array<f64, D::Smaller>
where
    T: RawData,
    D: Dimension
{
    let d = a.dim().into_dimension();
    let d = d.as_array_view();
    let d = d.as_slice().unwrap();
    let d = &d[..d.len() - 1];

    let mut d1 = D::Smaller::default();
    d1.as_array_view_mut().into_slice().unwrap().copy_from_slice(d);

    let v: Vec<f64> = vec![0.0; d1.size()];
    Array::from_shape_vec(d1, v).expect("dimensionality mismatch")
}

Playground

1 Like

Thanks, this seems to be working! I'm surprised it's such a complicated operation though, I was hoping there would be a shorter solution with nicer code. If there already existed a function to remove an axis from a given shape, for example, it would've been straightforward.

Digging a bit deeper in the documentation, there's a RemoveAxis trait which simplifies the removal of the last dimension, like this:

fn create_zeros<T, D>(a: ArrayBase<T, D>) -> Array<f64, D::Smaller>
where
    T: RawData,
    D: RemoveAxis
{
    let d = a.dim().into_dimension();
    let d1 = d.remove_axis(Axis(d.ndim() - 1));

    let v: Vec<f64> = vec![0.0; d1.size()];
    Array::from_shape_vec(d1, v).expect("dimensionality mismatch")
}
3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.