I am trying to use ndarray to calculate dot products, and am getting compilation errors that I don't understand.
My basic function is
use ndarray::{ArrayD, ArrayBase};
pub fn cosine<L>(v1: &ArrayBase<f64, L>, v2: &ArrayBase<f64, L>) -> f64 {
let x: f64 = v1.dot(&v2) / (v1.dot(v1) * v2.dot(v2)).sqrt();
return x
}
pub fn cosine2(v1: &ArrayD<f64>, v2: &ArrayD<f64>) -> f64 {
let x: f64 = v1.dot(v2) / (v1.dot(v1) * v2.dot(v2)).sqrt();
return x
}
which fails to compile:
error[E0277]: the trait bound `f64: ndarray::data_traits::RawData` is not satisfiedchgraph
--> src/simple.rs:3:1
|
3 | / pub fn cosine<L>(v1: &ArrayBase<f64, L>, v2: &ArrayBase<f64, L>) -> f64 {
4 | | let x: f64 = v1.dot(&v2) / (v1.dot(v1) * v2.dot(v2)).sqrt();
5 | | }
| |_^ the trait `ndarray::data_traits::RawData` is not implemented for `f64`
|
= note: required by `ndarray::ArrayBase`
If I comment out cosine, I get an error from cosine2:
error[E0599]: no method named `dot` found for reference `&ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<f64>, ndarray::dimension::dim::Dim<ndarray::dimension::dynindeximpl::IxDynImpl>>` in the current scope
--> src/simple.rs:9:21
|
9 | let x: f64 = v1.dot(v2) / (v1.dot(v1) * v2.dot(v2)).sqrt();
| ^^^ method not found in `&ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<f64>, ndarray::dimension::dim::Dim<ndarray::dimension::dynindeximpl::IxDynImpl>>`
(and two more copies for the other dot products). Why can the second version not find the method? It seems that ArrayD is a type based on Array, which is in turn a type based on ArrayBase, so ArrayD::dot should be an existing method.
I only need to be able to pass an ArrayD, so I am happy with a version of either that works.
The relevant parts of my Cargo.toml are
[dependencies.ndarray]
version = "0.13.1"
[features]
default = ["ndarray/blas"]
First of all, the data type of ArrayBase is not indexed by the data type, but a RawData wrapper of the data type. Second of all, dot requires the Dot trait to be implemented. So, you should add these both to the trait bounds:
use ndarray::linalg::Dot;
use ndarray::{ArrayBase, ArrayD, RawData};
pub fn cosine<D, L>(v1: &ArrayBase<D, L>, v2: &ArrayBase<D, L>) -> f64
where
D: RawData<Elem = f64>,
ArrayBase<D, L>: Dot<ArrayBase<D, L>, Output = f64>,
{
let x: f64 = v1.dot(&v2) / (v1.dot(v1) * v2.dot(v2)).sqrt();
return x;
}
Related
This question already has answers here:
What is the correct way to return an Iterator (or any other trait)?
(2 answers)
"Expected type parameter" error in the constructor of a generic struct
(1 answer)
Closed 2 years ago.
I want make the mapping portion of this line into a function:
let i: Vec<u32> = (0..=5).map(|x| x * 2).collect();
I wrote this code which I assumed would be a drop-in for what I removed from the original code:
let j: Vec<u32> = process(0..=5).collect();
fn process<I>(src: I) -> I
where
I: Iterator<Item = u32>,
{
src.map(|x| x * 2)
}
I get this compile time error:
error[E0308]: mismatched types
--> src/lib.rs:5:5
|
1 | fn process<I>(src: I) -> I
| - - expected `I` because of return type
| |
| this type parameter
...
5 | src.map(|x| x * 2)
| ^^^^^^^^^^^^^^^^^^ expected type parameter `I`, found struct `std::iter::Map`
|
= note: expected type parameter `I`
found struct `std::iter::Map<I, [closure#src/lib.rs:5:13: 5:22]>`
Playground
Since std::iter::Map<u32, u32> implements the Iterator trait, shouldn't it be able to be returned as Iterator<Item = u32>?
I was able to get it working with the following:
fn process<I>(src: I) -> std::iter::Map<I, Box<dyn Fn(u32) -> u32>>
where
I: Iterator<Item = u32>,
{
src.map(Box::new(|x| x * 2))
}
This involves wrapping the closure in a Box. Is there a better or less verbose way to do this that matches the inline function?
I'm trying to implement a generic function in Rust where the only requirement for the argument is that the multiplication operation should be defined. I'm trying to implement a generic "power", but will go with a simpler cube function to illustrate the problem:
use std::ops::Mul;
fn cube<T: Mul>(x: T) -> T {
x * x * x
}
fn main() {
println!("5^3 = {}", cube(5));
}
When compiling I get this error:
error[E0369]: binary operation `*` cannot be applied to type `<T as std::ops::Mul>::Output`
--> src/main.rs:4:5
|
4 | x * x * x
| ^^^^^^^^^
|
= note: an implementation of `std::ops::Mul` might be missing for `<T as std::ops::Mul>::Output`
What does this mean? Did I choose the wrong trait? How can I resolve this?
Let's break down your example a bit:
fn cube<T: Mul>(x: T) -> T {
let a = x * x;
let b = a * x;
b
}
What are the types of a and b? In this case, the type of a is <T as std::ops::Mul>::Output — sound familiar from the error message? Then, we are trying to multiply that type by x again, but there's no guarantee that Output is able to be multiplied by anything!
Let's do the simplest thing and say that T * T needs to result in a T:
fn cube<T: Mul<Output = T>>(x: T) -> T {
x * x * x
}
Unfortunately, this gives two similar errors:
error[E0382]: use of moved value: `x`
--> src/lib.rs:6:9
|
6 | x * x * x
| - ^ value used here after move
| |
| value moved here
|
= note: move occurs because `x` has type `T`, which does not implement the `Copy` trait
Which is because the Mul trait takes arguments by value, so we add the Copy so we can duplicate the values.
I also switched to the where clause as I like it better and it is unwieldy to have that much inline:
fn cube<T>(x: T) -> T
where
T: Mul<Output = T> + Copy
{
x * x * x
}
See also:
How do I implement the Add trait for a reference to a struct?
How to write a trait bound for adding two references of a generic type?
The bound T: Mul does not imply that the result of the binary operator is also of type T. The result type is an associated type of this trait: Output.
The other issue is that before Rust 1.0 the operator traits switched from pass-by-reference to pass-by-value. In generic code this can be a bit of a pain in the butt (for now at least) because these operators consume their operands unless you also require the types to be Copy.
Just for completeness (in case you don't like to require Copy), let me add some information about a possible alternative direction.
For the sake of generic code, authors of "numeric types" are encouraged to provide additional non-consuming implementations of these operator traits so that you don't need Copy or Clone. For example, the standard library already provides the following implementations:
f64 implements Mul< f64>
f64 implements Mul<&f64>
&f64 implements Mul< f64>
&f64 implements Mul<&f64>
Each of these implementations has f64 as the Output type. Making use of these traits directly is not pretty:
fn cube<T>(x: &T) -> T
where
for<'a> T: Mul<&'a T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
x * x * x
}
Eventually, we might get some (slightly) higher level traits, which would reduce the noise. For example: T: Mul2 could imply T: Mul<T> + Mul<&T> and &T: Mul<T> + Mul<&T>, but at the time of writing this, the Rust compiler does not seem able to handle this. At least I could not successfully compile the following code:
use std::ops::Mul;
pub trait Mul2
where
Self: Mul<Self, Output = Self>,
Self: for<'a> Mul<&'a Self, Output = Self>,
for<'a> &'a Self: Mul<Self, Output = Self>,
for<'a, 'b> &'a Self: Mul<&'b Self, Output = Self>,
{
}
impl<T> Mul2 for T
where
T: Mul<T, Output = T>,
T: for<'a> Mul<&'a T, Output = T>,
for<'a> &'a T: Mul<T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
}
fn cube<T: Mul2>(x: &T) -> T {
x * x * x
}
fn main() {
let c = cube(&2.3);
println!("Hello, world! {}", c)
}
I think it's safe to say that things will improve in this area. For now, the ability to generically implement numeric algorithms in Rust is not as good as I would like it to be.
What's the proper type annotation in the following code to convert an integer to a float?
use conv::{ValueInto, errors::PosOverflow};
fn run_me() -> Result <f32, PosOverflow<usize>> {
let m: f32 = 21.3;
let n: usize = 23;
let p: f32 = n.value_into()?;
let bar = m * p;
let baz = m * (n.value_into()?); // Compiler error here
Ok(baz)
}
fn main() {
run_me();
}
Which fails with:
error[E0277]: cannot multiply `()` to `f32`
--> src/main.rs:7:17
|
7 | let baz = m * (n.value_into()?);
| ^ no implementation for `f32 * ()`
|
= help: the trait `std::ops::Mul<()>` is not implemented for `f32`
error[E0277]: the trait bound `(): conv::ValueFrom<usize>` is not satisfied
--> src/main.rs:7:22
|
7 | let baz = m * (n.value_into()?);
| ^^^^^^^^^^ the trait `conv::ValueFrom<usize>` is not implemented for `()`
|
= note: required because of the requirements on the impl of `conv::ValueInto<()>` for `usize`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
error: Could not compile `tmp3`.
To learn more, run the command again with --verbose.
Basically, a conversion from usize to f32 could fail, so we have the conv package to handle the details. In the following code, the bar computes just fine, but baz does not. I'd like a one liner like baz to work directly because more complicated examples will need to chain together multiple conversions.
Edit 1
Ok, so I can force what I want by adding a trait to usize. Is there a problem with this approach or can the original call to value_into be fixed?
use conv::{ValueFrom, ValueInto, errors::PosOverflow};
trait ToF32 {
fn to_f32(self) -> Result<f32, PosOverflow<usize>>;
}
impl ToF32 for usize {
fn to_f32(self) -> Result<f32, PosOverflow<usize>> {
f32::value_from(self)
}
}
fn run_me() -> Result <f32, PosOverflow<usize>> {
let m: f32 = 21.3;
let n: usize = 23;
let p: f32 = n.value_into()?;
let bar = m * p;
let baz = m * n.to_f32()?;
// let buz = m * n.value_into()?;
Ok(baz)
}
fn main() {
run_me();
}
Some functions in Rust like value_into and try_into have to be called when assigning to directly to a typed variable.
To answer your question directly, the proper way to add type annotations is by assigning it into a temporary variable (like you did with bar and p) before using the value.
This is related to my earlier question on making a modular exponentiation method generic. I've now arrived at the following code:
fn powm<T>(fbase: &T, exponent: &T, modulus: &T) -> T
where
T: Mul<T, Output = T>
+ From<u8>
+ PartialEq<T>
+ Rem<T, Output = T>
+ Copy
+ for<'a> Rem<&'a T, Output = T>
+ Clone
+ PartialOrd<T>
+ ShrAssign<T>,
for<'a> &'a T: PartialEq<T> + Rem<&'a T, Output = T>,
{
if modulus == T::from(1) {
T::from(0)
} else {
let mut result = T::from(1);
let mut base = fbase % modulus;
let mut exp = exponent.clone();
while exp > T::from(0) {
if exp % T::from(2) == T::from(1) {
result = (result * base) % modulus;
}
exp >>= T::from(1);
base = (base * base) % modulus;
}
result
}
}
It is my understanding that by defining the trait bound where for<'a> &'a T: Rem<&'a T, Output=T> that it is understood that I can use the modulo operator % on two operands of type &'a T, and the result will be of type T. However, I get the following error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:20:30
|
20 | let mut base = fbase % modulus;
| ^
|
note: first, the lifetime cannot outlive the anonymous lifetime #3 defined on the function body at 3:1...
--> src/main.rs:3:1
|
3 | / fn powm<T>(fbase: &T, exponent: &T, modulus: &T) -> T
4 | | where
5 | | T: Mul<T, Output = T>
6 | | + From<u8>
... |
30 | | }
31 | | }
| |_^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:20:32
|
20 | let mut base = fbase % modulus;
| ^^^^^^^
note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the function body at 3:1...
--> src/main.rs:3:1
|
3 | / fn powm<T>(fbase: &T, exponent: &T, modulus: &T) -> T
4 | | where
5 | | T: Mul<T, Output = T>
6 | | + From<u8>
... |
30 | | }
31 | | }
| |_^
note: ...so that types are compatible (expected std::ops::Rem, found std::ops::Rem<&T>)
--> src/main.rs:20:30
|
20 | let mut base = fbase % modulus;
| ^
The code does work if I replace the line in question by
let mut base = fbase.clone() % modulus;
I don't see why I would need to clone in the first place if I can use the modulo operator already to return a "fresh" element of type T. Do I need to modify my trait bounds instead? Why does this go wrong?
When programming, it's very useful to learn how to create a Minimal, Complete, and Verifiable example (MCVE). This allows you to ignore irrelevant details and focus on the core of the problem.
As one example, your entire blob of code can be reduced down to:
use std::ops::Rem;
fn powm<T>(fbase: &T, modulus: &T)
where
for<'a> &'a T: Rem<&'a T, Output = T>,
{
fbase % modulus;
}
fn main() {}
Once you have a MCVE, you can make permutations to it to explore. For example, we can remove the lifetime elision:
fn powm<'a, 'b, T>(fbase: &'a T, modulus: &'b T)
where
for<'x> &'x T: Rem<&'x T, Output = T>,
{
fbase % modulus;
}
Now we start to see something: what is the relation between all three lifetimes? Well, there isn't one, really. What happens if we make one?
If we say that the input references can be unified to the same
lifetime, it works:
fn powm<'a, T>(fbase: &'a T, modulus: &'a T)
If we say that 'b outlives 'a, it works:
fn powm<'a, 'b: 'a, T>(fbase: &'a T, modulus: &'b T)
If we say that we can have two different lifetimes in the operator, it works:
for<'x, 'y> &'x T: Rem<&'y T, Output = T>,
What about if we poke at the call site?
If we directly call the Rem::rem method, it works:
Rem::rem(fbase, modulus);
If we dereference and re-reference, it works:
&*fbase % &*modulus;
I don't know exactly why the original doesn't work — conceptually both the input references should be able to be unified to one lifetime. It's possible that there's a piece of inference that either cannot or isn't happening, but I'm not aware of it.
Some further discussion with a Rust compiler developer led to an issue as it doesn't quite seem right. This issue has now been resolved and should theoretically be available in Rust 1.23.
This question already has answers here:
How do I update a variable in a loop to a reference to a value created inside the loop?
(2 answers)
How to abstract over a reference to a value or a value itself?
(1 answer)
Is it possible to return either a borrowed or owned type in Rust?
(1 answer)
Closed 5 years ago.
I'm trying to learn Rust by translating C++ code from the "Elements of Programming" book by Stepanov and McJones. Here's a simple code snippet:
extern crate num_bigint;
use num_bigint::BigInt;
pub fn fibonacci_matrix_multiply(x: (&BigInt, &BigInt), y: (&BigInt, &BigInt)) -> (BigInt, BigInt) {
(x.0 * (y.1 + y.0) + x.1 * y.0, x.0 * y.0 + x.1 * y.1)
}
pub fn power_accumulate_positive(
mut r: (&BigInt, &BigInt),
mut a: (&BigInt, &BigInt),
mut n: i32,
) -> (BigInt, BigInt) {
loop {
if n & 1 == 1 {
r = fibonacci_matrix_multiply(r, a);
if n == 1 {
return r;
}
}
a = fibonacci_matrix_multiply(a, a);
n = n / 2;
}
}
fn main() {}
Here's the error messages:
error[E0308]: mismatched types
--> src/main.rs:16:17
|
16 | r = fibonacci_matrix_multiply(r, a);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found struct `num_bigint::BigInt`
|
= note: expected type `(&num_bigint::BigInt, &num_bigint::BigInt)`
found type `(num_bigint::BigInt, num_bigint::BigInt)`
error[E0308]: mismatched types
--> src/main.rs:18:24
|
18 | return r;
| ^ expected struct `num_bigint::BigInt`, found reference
|
= note: expected type `(num_bigint::BigInt, num_bigint::BigInt)`
found type `(&num_bigint::BigInt, &num_bigint::BigInt)`
error[E0308]: mismatched types
--> src/main.rs:21:13
|
21 | a = fibonacci_matrix_multiply(a, a);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found struct `num_bigint::BigInt`
|
= note: expected type `(&num_bigint::BigInt, &num_bigint::BigInt)`
found type `(num_bigint::BigInt, num_bigint::BigInt)`
I understand that I'm returning a tuple of structs and trying to assign it to a tuple of references, but I don't know how to solve the problem.
Is there a reason you can't take the BigInts by value instead of by reference? This would remove all the borrow checker errors. Unless it's a clear and measured bottleneck to clone the BigInts, passing by reference won't be much faster and it's less ergonomic.
Here's a working solution that doesn't use references (and instead clones the values)
extern crate num_bigint;
use num_bigint::BigInt;
pub fn fibonacci_matrix_multiply(x: (BigInt, BigInt), y: (BigInt, BigInt)) -> (BigInt, BigInt) {
(&x.0 * (&y.1 + &y.0) + &x.1 * &y.0, x.0 * y.0 + x.1 * y.1)
}
pub fn power_accumulate_positive(
mut r: (BigInt, BigInt),
mut a: (BigInt, BigInt),
mut n: i32,
) -> (BigInt, BigInt) {
loop {
if n & 1 == 1 {
r = fibonacci_matrix_multiply(r, a.clone());
if n == 1 {
return r;
}
}
a = fibonacci_matrix_multiply(a.clone(), a);
n = n / 2;
}
}