Есть ли хороший способ сделать копию с перекрытием в ndarray в ржавчине?

Вот что я пробовал

use ndarray::{arr2, s};
let mut a = arr2(&[[1, 2, 3],
                   [4, 5, 6]]);
let b = arr2(&[[2, 3, 3],
               [5, 6, 6]]);

a.slice_mut(s![.., ..2]).assign(&a.slice_mut(s![.., 1..]));

который явно не работает из-за правил заимствования (ссылка на игровую площадку ):

error[E0499]: cannot borrow `a` as mutable more than once at a time
  --> src/main.rs:13:38
   |
13 |     a.slice_mut(s![.., ..2]).assign(&a.slice_mut(s![.., 1..]));
   |     -                        ------  ^ second mutable borrow occurs here
   |     |                        |
   |     |                        first borrow later used by call
   |     first mutable borrow occurs here

Вот a то, что у меня есть, и b это то, что я пытаюсь получить.

В numpy это так же просто, как a[:, :2] = a[:, 1:].

PS Может есть в nalgebra обрешетке простое решение?


person Antony Hatchkins    schedule 29.08.2019    source источник
comment
Почему бы вам не написать цикл for?   -  person Boiethios    schedule 30.08.2019
comment
@FrenchBoiethios только один цикл for не решит всех проблем с псевдонимом, которые могут возникнуть (например, копирование слева направо или копирование справа налево). Также я ожидал, что библиотека сделает это за меня или, по крайней мере, поможет мне в этом. В противном случае я бы прибегнул к простому C.   -  person Antony Hatchkins    schedule 30.08.2019


Ответы (2)


В главной ветке ndarray есть специальный макрос для этого, более удобный, чем split_at_mut(), поскольку он поддерживает произвольные срезы, но при наложении срезов возникает паника:

use ndarray::multislice;
use ndarray::prelude::*;
let mut arr: Array1<_> = (0..4).collect();
let (mut a, mut b) = multislice!(arr, mut [..;2], mut [1..;2]);
a.assign(&b);

дает [1,1,3,3]

Они даже решают диофантово уравнение, чтобы проверить это. Это происходит во время выполнения, а не во время компиляции split_at_mut.

person Antony Hatchkins    schedule 30.08.2019

Хорошо понял

use ndarray::{arr2, s,Array};

let mut a = arr2(&[[1, 2, 3],
                   [4, 5, 6]]);
unsafe{
    let b = a.as_mut_ptr();
    let c = Vec::<i32>::from_raw_parts(b, 6, 6);
    let mut d = Array::from_shape_vec((2, 3), c).unwrap();
    a.slice_mut(s![.., ..2]).assign(&d.slice_mut(s![.., 1..]));
    std::mem::forget(d);
}
println!("{:?}",a);
person Antony Hatchkins    schedule 29.08.2019
comment
Обратите внимание, что нет гарантии, что этот код будет работать: порядок, в котором assign перемещает элементы, не определен, поэтому будущая версия Rust или ndarray может нарушить ваш код. - person Jmb; 30.08.2019
comment
Это также не сработало бы, если бы вы захотели переместить данные вправо, а не влево ... - person Jmb; 30.08.2019
comment
Эта программа ведет к неопределенному поведению. - person E_net4 the curator; 30.08.2019
comment
@Jmb да, для этого нужна некоторая логика, аналогичная реализации memmove: перевернуть срез, если движение влево - person Antony Hatchkins; 30.08.2019