How to copy a slice in Array3 (ndarray)

Dear all,

I need help please. I'm using an ndarray crate. I would like to copy or clone a slice of an Array3. Given the following arrays:

    // initialise electric field values Ex
    let mut ex = Array3::<f32>::zeros((NX, NY, NZ));

    // electric field values @ boundary planes @ time step m=n-1
    let mut ex_jmin_m = Array3::<f32>::zeros((NX,2,NZ));

I can do it the explicit loop way:

for i in IMIN+1..IMAX {
        for j in JMIN+1..JMAX {

            // Ex @ jmin, jmax
            ex_jmin_m[[i,0,k]] = ex[[i,JMIN+1,k]];
            ex_jmin_m[[i,1,k]] = ex[[i,JMIN+2,k]];
        }
    }

But how do I do it in an idiomatic Rust (rustic/rusty way)? I tried using slices and clone():

error[E0599]: the method `clone` exists for struct `ArrayBase<ViewRepr<&mut f32>, Dim<[usize; 3]>>`, but its trait bounds were not satisfied
    --> src/main.rs:164:79
     |
164  |     ex_jmin_m = ex.slice_mut(s![IMIN+1..IMIN, JMIN+1..=JMIN+2, KMIN+1..KMAX]).clone();
     |                                                                               ^^^^^ method cannot be called on `ArrayBase<ViewRepr<&mut f32>, Dim<[usize; 3]>>` due to unsatisfied trait bounds
     |
    ::: /Users/mabalenk/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ndarray-0.15.6/src/lib.rs:1268:1
     |
1268 | pub struct ArrayBase<S, D>
     | -------------------------- doesn't satisfy `_: Clone`
...
1459 | pub struct ViewRepr<A> {
     | ---------------------- doesn't satisfy `ViewRepr<&mut f32>: RawDataClone`
     |
     = note: the following trait bounds were not satisfied:
             `ViewRepr<&mut f32>: RawDataClone`
             which is required by `ArrayBase<ViewRepr<&mut f32>, Dim<[usize; 3]>>: Clone`

I attempted using slices and assign_to():

    ex.slice(s![IMIN+1..IMIN, JMIN+1..=JMIN+2, KMIN+1..KMAX]).assign_to(ex_jmin_m);
    println!("shape(ex_jmin_m): {:?}", &ex_jmin_m.shape());

But the compilation fails with the following error:

error[E0382]: borrow of moved value: `ex_jmin_m`
   --> src/main.rs:160:40
    |
133 |           ex_jmin_m: &mut Array3<f32>, ex_jmax_m: &mut Array3<f32>,
    |           --------- move occurs because `ex_jmin_m` has type `&mut ArrayBase<OwnedRepr<f32>, Dim<[usize; 3]>>`, which does not implement the `Copy` trait
...
159 |     ex.slice(s![IMIN+1..IMIN, JMIN+1..=JMIN+2, KMIN+1..KMAX]).assign_to(ex_jmin_m);
    |                                                                         --------- value moved here
160 |     println!("shape(ex_jmin_m): {:?}", ex_jmin_m.shape());
    |                                        ^^^^^^^^^^^^^^^^^ value borrowed here after move

You are probably turning ex_jmin_m itself into a mutable borrow somewhere, because if I keep it owned and pass an explicit borrow (which should be expected when calling a function named assign_to), then it works.

(Even if you want to keep ex_jmin_m as a mutable reference, you can pass a reborrow of it, &mut *ex_jmin_m, instead of giving it away by-value, like this.)

2 Likes

Thank you for your reply! But I feel this is getting unnecessarily complicated. Especially passing a reborrow...

I don't get what can possibly be considered excessively complicated in a single borrow.

By the way, the code that you showed doesn't compile for a different reason (assign_to expects a reference argument), so you are clearly not showing key parts of your actual code.

1 Like

Yes, let me try to create a minimalistic example and get back to you.

I have composed a minimalistic example of my use case:

extern crate ndarray;

use ndarray::{Array1, s};

fn main() {

    const N: usize = 10;
    const T: usize =  3;

    let mut a = Array1::<f32>::zeros(N);

    for i in 0..N {
        a[i] = i as f32;
    }

    let mut a_min = Array1::<f32>::zeros(2);

    a.slice(s![..2]).assign_to(a_min.slice_mut(s![..2]));

    for t in 0..T {

        a *= t as f32 + 1.0;
        println!("{:?}", a);

        a.slice(s![..2]).assign_to(a_min.slice_mut(s![..2]));
        println!("{:?}", a_min);
    }
}

It works! Now I need to expand and transfer it to my realistic program. May I please ask you is assign_to a suitable method to use or is there a shorter, more elegant method?

My task is to copy boundary values of a main array into an auxiliary array at each time step of my simulation.