0

I find it impossible to do a subtraction between an immutable array reference and a mutable one using the ndarray crate:

#[macro_use]
extern crate ndarray;

use ndarray::Array1;

fn main() {
    let a: &Array1<f64> = &array![3.0, 2.0, 1.0];
    let b: &mut Array1<f64> = &mut array![1.0, 1.0, 1.0];
    let c = a - &b.view();          //   This compiles
    let d = a - b;                  //   This fails to compile
}

The error message I get is:

let d = a - b;
          ^ no implementation for `f64 - &mut ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 1]>>`

I don't understand what these two types mean, but is there any special reason why this is not implemented?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
asdetrefle
  • 303
  • 1
  • 6
  • 14

2 Answers2

2

The Sub trait in ndarray::ArrayBase is not implemented for &mut arguments (it is for immutable references to other arrays). It is not needed because the right-handed value should not be modified. The second operand is a &mut Array<A, D>, and it ends up being one of the cases where type weakening into an immutable reference does not happen automatically. Still, you can explicitly reborrow the value:

let a: &Array1<f64> = &array![3.0, 2.0, 1.0]; 
let b: &mut Array1<f64> = &mut array![1.0, 1.0, 1.0]; 
let c = a - &b.view();
let d = a - &*b;

This assumes that a and b were obtained elsewhere. In fact, you can make these variables own the arrays instead:

let a: Array1<f64> = array![3.0, 2.0, 1.0]; 
let mut b: Array1<f64> = array![1.0, 1.0, 1.0]; 
let c = &a - &b.view();
let d = &a - &b;
E_net4
  • 27,810
  • 13
  • 101
  • 139
1

The full error message is:

error[E0277]: the trait bound `f64: std::ops::Sub<&mut ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 1]>>>` is not satisfied
  --> src/main.rs:10:15
   |
10 |     let d = a - b;
   |               ^ no implementation for `f64 - &mut ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 1]>>`
   |
   = help: the trait `std::ops::Sub<&mut ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 1]>>>` is not implemented for `f64`
   = note: required because of the requirements on the impl of `std::ops::Sub<&mut ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 1]>>>` for `&ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 1]>>`

error[E0277]: the trait bound `&mut ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 1]>>: ndarray::ScalarOperand` is not satisfied
  --> src/main.rs:10:15
   |
10 |     let d = a - b;
   |               ^ the trait `ndarray::ScalarOperand` is not implemented for `&mut ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 1]>>`
   |
   = note: required because of the requirements on the impl of `std::ops::Sub<&mut ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 1]>>>` for `&ndarray::ArrayBase<ndarray::OwnedRepr<f64>, ndarray::Dim<[usize; 1]>>`

The first error message is quite obscure for me but the second is more enlightening:

the trait ndarray::ScalarOperand is not implemented for `&mut ndarray::ArrayBase

The reason of this error is that Rust does not perform coercions when matching traits: If there is an impl for some type U and T coerces to U, that does not constitute an implementation for T (copied directly from the Nomicon)

Without entering into ndarray internals, this is a minimal example reproducing the same problem:

trait MyShape {}

fn foo<T: MyShape>(x: T) -> T {
    x
}

impl<'a> MyShape for &'a i32 {}

fn main() {
    let mut num = 1;
    let arg: &mut i32 = &mut num;
    foo(arg);
}

Result:

error[E0277]: the trait bound `&mut i32: MyShape` is not satisfied
  --> src/main.rs:12:5
   |
12 |     foo(arg);
   |     ^^^ the trait `MyShape` is not implemented for `&mut i32`
   |
   = help: the following implementations were found:
             <&'a i32 as MyShape>
   = note: required by `foo`
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
attdona
  • 17,196
  • 7
  • 49
  • 60
  • May I ask how you copied your error messages? They lost whitespace before the `|` (they should all be lined up). I've seen this a bunch, but don't know what causes it. – Shepmaster Mar 23 '18 at 14:08
  • I copied output from terminal into visual studio code, I selected all and added a tab (4 spaces) to the selected text. – attdona Mar 23 '18 at 14:12