Using ndarray. This playground snippet says it all -- I want to multiply a matrix view element-wise with a matrix, and I can't figure out a combination of views and casts and whatnot that'll make it work.
#![allow(unused)]
use ndarray::{Array1, Array2, Axis};
fn main () {
let bob = Array1::from(vec![1.2, 3.3, 4.]);
let ralph = Array2::from(vec![[3.3, 1.0, -2.0],[4., 5., 8.], [-9., 2., 1.]]);
println!("{:?}", ralph.index_axis(Axis(1), 0) * bob);
}
On compilation gives the error:
error[E0369]: cannot multiply `ArrayBase<ViewRepr<&{float}>, Dim<[usize; 1]>>` by `ArrayBase<OwnedRepr<{float}>, Dim<[usize; 1]>>`
--> src/lib.rs:8:51
|
8 | println!("{:?}", ralph.index_axis(Axis(1), 0) * bob);
| ---------------------------- ^ --- ArrayBase<OwnedRepr<{float}>, Dim<[usize; 1]>>
| |
| ArrayBase<ViewRepr<&{float}>, Dim<[usize; 1]>>
Is there a magic finger-ring combination that'll make it do what I want, or do I need to do it by hand?
Adding a & to both elements of the multiplication will prevent either value from being consumed in the process of multiplication:
&ralph.index_axis(Axis(1), 0) * &bob
The following link from the ndarray docs explains allocating a new array vs consuming the array during binary operations: https://docs.rs/ndarray/0.14.0/ndarray/struct.ArrayBase.html#binary-operators-with-two-arrays
I think because the result of index_axis() is a view into another array, it can't be consumed safely, hence the error
Swapping the order of the operations also fixes it:
#![allow(unused)]
use ndarray::{Array1, Array2, Axis};
fn main () {
let bob = Array1::from(vec![1.2, 3.3, 4.]);
let ralph = Array2::from(vec![[3.3, 1.0, -2.0],[4., 5., 8.], [-9., 2., 1.]]);
println!("{:?}", bob * ralph.index_axis(Axis(1), 0));
}
Related
There is a roll function in Numpy. But ndarray docs don't mention anything similar.
I am trying to "roll" my array by an integer. For example
let ar = arr2(&[[1.,2.,3.], [7., 8., 9.]]);
calling numpy roll(ar, 1) would produce the desired result:
[[3.,1., 2.],
[9., 7., 8.]]
Is there an alternative for ndarray in rust or a workaround?
Update:
Found this old open thread, not sure if any more up to date solution has been implemented: https://github.com/rust-ndarray/ndarray/issues/281
Ndarray documentation provides an example:
https://docs.rs/ndarray/latest/ndarray/struct.ArrayBase.html#method.uninit
However, it did not give expected result. I ammended it slightly:
/// Shifts 2D array by {int} to the right
/// Creates a new Array2 (cloning)
fn shift_right_by(by: usize, a: &Array2<f64>) -> Array2<f64> {
// if shift_by is > than number of columns
let x: isize = (by % a.len_of(Axis(1))) as isize;
// if shift by 0 simply return the original
if x == 0 {
return a.clone();
}
// create an uninitialized array
let mut b = Array2::uninit(a.dim());
// x first columns in b are two last in a
// rest of columns in b are the initial columns in a
a.slice(s![.., -x..]).assign_to(b.slice_mut(s![.., ..x]));
a.slice(s![.., ..-x]).assign_to(b.slice_mut(s![.., x..]));
// Now we can promise that `b` is safe to use with all operations
unsafe { b.assume_init() }
}
I am toying around with Rust, and am trying to take in some input, and then splitting it by white space in to a vector of strings.
I then want to destructure these inputs again in to separate values. What I have so far is this:
use std::io;
fn main() {
println!("___Calculator___");
let mut buffer = String::new();
println!("What would you like to calculate?");
io::stdin()
.read_line(&mut buffer)
.unwrap();
let elements = buffer
.split_whitespace()
.collect::<Vec<&str>>();
let [first, second, third] = elements[0..2];
}
Again, I know I could just read input 3 times, but I want to see how I can do different things with the language.
Edit
Here's the error from cargo run:
Compiling calculator v0.1.0 (E:\code\rust\calculator)
error[E0005]: refutable pattern in local binding: `[]`, `[_]`, `[_, _]` and 1 more not covered
--> src\main.rs:18:9
|
18 | let [first, second, third] = elements[0..2];
| ^^^^^^^^^^^^^^^^^^^^^^ patterns `[]`, `[_]`, `[_, _]` and 1 more not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `[&str]`
help: you might want to use `if let` to ignore the variants that aren't matched
|
18 | let (first, second, third) = if let [first, second, third] = elements[0..2] { (first, second, third) } else { todo!() };
| +++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++
For more information about this error, try `rustc --explain E0005`.
error: could not compile `calculator` due to previous error
Thanks
Rust doesn't understand that elements[0..2] is always going to be three elements. In fact, it potentially won't be, if the user enters fewer than three words. So you need to handle that case.
if let [first, second, third] = &elements[0..2] {
...
} else {
println!("Enter three words plz :(");
}
EDIT: From a comment on the question, you also want elements[0..3]. Ranges are half-open in Rust.
The compiler is telling you what the problem is, and even suggests a fix:
error[E0005]: refutable pattern in local binding: `[]`, `[_]`, `[_, _]` and 1 more not covered
--> src/main.rs:18:9
|
18 | let [first, second, third] = elements[0..2];
| ^^^^^^^^^^^^^^^^^^^^^^ patterns `[]`, `[_]`, `[_, _]` and 1 more not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `[&str]`
help: you might want to use `if let` to ignore the variants that aren't matched
|
18 | let (first, second, third) = if let [first, second, third] = elements[0..2] { (first, second, third) } else { todo!() };
| +++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++
Patterns in variable declarations are required to be irrefutable, i.e. always succeed. What if the vector has less than three elements? You have to use match or if let to cover that possibility.
How to push an item (struct type) from vector1 to vector2 in Rust? Can someone help me?
let mut vec1: Vec<Struct1> = vec![];
let item1 = Struct1 {
id: 1,
name: "AlgoQ".to_string()
};
vec1.push(item1);
let mut vec2: Vec<Struct1> = vec![];
vec2.push(&vec1[0]);
vec1.pop();
Error:
error[E0308]: mismatched types
--> src/test4.rs:17:15
|
17 | vec2.push(&vec1[0]);
| ^^^^^^^^
| |
| expected struct `Struct1`, found `&Struct1`
| help: consider removing the borrow: `vec1[0]`
Your item can't be at both place. You have to either
remove the item from the source vector:
vec2.push(vec1.remove(0));
Here, as you also want to pop from the first vector, you may directly do
if let Some(item) = vec1.pop() {
vec2.push(item);
}
But be careful that pop removes at the end, not at index 0 so your snippet is a little obscure regarding your exact intent.
or clone the item (assuming it can be cloned)
vec2.push(vec1[0].clone());
Now, if you really want the item to be, conceptually, at two places, you may store references (ie &Struct1) or indexes in your second vec.
I'm trying to remove some elements from a vector, based on a predicate, and collecting the result. Here's a (not working) example with an expected result:
let mut v: Vec<i32> = vec![1, 2, 3, 4, 5, 6];
let drained: Vec<i32> = v.iter().filter(|e| (*e) % 2 == 0).drain(..).collect();
assert_eq!(v, vec![1, 3, 5]);
assert_eq!(drained, vec![2, 4, 6]);
This results in the error
error[E0599]: no method named `drain` found for type `std::iter::Filter<std::slice::Iter<'_, i32>, [closure#src/main.rs:4:45: 4:62]>` in the current scope
--> src/main.rs:4:64
|
4 | let drained: Vec<i32> = v.iter().filter(|e| (*e) % 2 == 0).drain(..).collect();
| ^^^^^
There are several alternatives I looked at, none of them seem to be doing what I want:
Vec::retain removes the elements from the vector, but doesn't give back ownership of the removed elements.
v.drain(..).filter(condition).collect() returns the correct value for drained but empties the whole vector.
Not in stable Rust 1.33.0. There's an unstable nightly feature called drain_filter that does exactly what you want:
#![feature(drain_filter)]
fn main() {
let mut v: Vec<i32> = vec![1, 2, 3, 4, 5, 6];
let drained: Vec<i32> = v.drain_filter(|&mut e| e % 2 == 0).collect();
assert_eq!(v, vec![1, 3, 5]);
assert_eq!(drained, vec![2, 4, 6]);
}
As a stable workaround, you may be able to use Iterator::partition, but it does not reuse the memory:
fn main() {
let v: Vec<i32> = vec![1, 2, 3, 4, 5, 6];
let (drained, v): (Vec<_>, Vec<_>) = v.into_iter().partition(|&e| e % 2 == 0);
assert_eq!(v, vec![1, 3, 5]);
assert_eq!(drained, vec![2, 4, 6]);
}
The documentation state that Vec.retain will operate in-place, and visit each element in order, exactly once.
fn drain_where<T, Pred : Fn(&T) -> bool>(source: &mut Vec<T>, pred: Pred) -> Vec<T>
where T : Copy {
let mut drained: Vec<T> = Vec::new();
source.retain(|item| {
if pred(item) { drained.push(*item); false } else { true }
});
drained
}
I can suggest few other ways to do this + my benchmarks.
N.B. I compare all methods by few criteria:
Does it support external source of truth (my use-case). E.g. Vec::retain supports that, meaning that you can write code like
// conditions: &[bool]
assert_eq!(conditions.len(), my_vec.len());
let cond = conditions.iter().copied();
my_vec.retain(move|_|cond.next().unwrap());
Is method supported by third-party Vecs, namely ArrayVec, TinyVec, SmallVec, FixedSliceVec and others.
Is it fast.
So, let's begin
Sort slice than split slice
Features:
Can support external source of truth — No ❌. Would call closure O(n log n) times in unspecified order so support only predicates which calculated only directly from values.
Third-party support — Excellent ✅. You can use it on anything convertible to mutable slice.
Is it fast — In generic case, no ❌. It runs for O(n log n) time while other methods run for O(n) time. However, if preserving original relative order is not important for you, you can use sort_unstable_by_key which doesn't allocate memory at all, which can make it fastest in some scenarios.
Implementation:
v.sort_by_key(|x| predicate(x));
let split_pos = v.partition_point(|x| predicate(x));
let (false_slice, true_slice) = v.split_at_mut(split_pos)
Vec::drain_filter
Can support external source of truth — Yes ✅. Visits items in original order exactly one time.
Third-party support — Non existent ❌. Also, you can't it even use in stable Rust and it's tracking issue has been suffering from bikeshedding 5 years now (at 2022-07).
Is it fast — Yes ✅.
Code
let removed_items: Vec<_> = v.drain_filter(|x| predicate(x)).collect();
MaybeUninit trick using unsafe code
Well, I wrote it myself.
Features:
Can support external source of truth — Yes ✅. Visits items in original order exactly one time.
Third-party support — Supported ✅. Note that you must audit their implementation of retain to ensure that it cannot panic itself.
Is it fast — Yes ✅. In my benchmarks it is faster than Vec::drain_filter.
This implementation makes 2 assumptions:
Internal layout of Vec<T> and Vec<MaybeUninit<T>> is same. There is no reason why it is not because memory layout of T and MaybeUninit<T> is same but I also verify this using asserts. Note that asserts would be removed by compiler optimizer because they are always true.
retain doesn't panic itself (it can only propagate panics from element drop or from predicate). This is true for std::vec::Vec but you need to ensure that for third-party crates.
Algorithm is simple:
reinterpret initial vector Vec<T> as Vec<MaybeUninit<T>>;
wrap our predicate into new predicate that moves items which we want to remove into external storage;
let Vec::retain handle removal of items.
Also, only reason of usage of MaybeUninit and unsafe is avoiding double-frees so if your elements implement Copy, this algorithm can be implemented in safe Rust.
However, in that case you can just use filter(...).collect() and retain with almost same performance.
So, code is below with all comments why it is safe (note that I didn't test it using sanitizers or Miri so use it on your own risk):
/// Returns removed values.
fn retain_unsafe_generic<T: Sized>(
v: &mut Vec<T>,
mut which_to_keep: impl FnMut(&T) -> bool,
) -> Vec<T> {
use std::mem::{transmute, MaybeUninit};
/// # Safety
/// Caller must ensure that if it makes living copies of inner items,
/// those items is removed from original vec before original reference became usable again.
unsafe fn as_uninits<T: Sized>(v: &mut Vec<T>) -> &mut Vec<MaybeUninit<T>> {
let orig_ptr = v.as_ptr();
let orig_cap = v.capacity();
let orig_size = v.len();
let v: &mut Vec<MaybeUninit<T>> = unsafe {
// Safety: since `MaybeUninit` has same memory layout
// as wrapped type, we assume that we can treat vec with T
// as MaybeUninit<T>. This assumption checked by asserts below.
//
// Lifetimes of elements must be correctly enforced by caller.
transmute(v)
};
// Check if layout of Vec with different element type remains same.
assert_eq!(v.len(), orig_size);
assert_eq!(v.capacity(), orig_cap);
assert_eq!(v.as_ptr(), orig_ptr.cast());
v
}
let mut res: Vec<T> = Vec::with_capacity(v.len());
let v = unsafe {
// Safety: we keep result reference only in `retain` call.
// We would remove all moved elements using retain.
as_uninits(v)
};
v.retain(
// Safety: `Vec::retain` would remove all items which values we moved into `res`.
// It wouldn call `drop::<T>` for removed values
// because `MaybeUninit` never drops wrapped values.
|x| unsafe {
// Safety: it is safe because `Vec::retain` visits elements sequentally
// so we haven't moved value from `x` yet.
// https://doc.rust-lang.org/std/vec/struct.Vec.html#method.retain
let val = &*x.as_ptr();
if which_to_keep(val) {
return true;
}
res.reserve(1);
// Any panic before this place is safe because
// 1. We didn't moved value from `x` yet;
// 2. In case of panic in predicate, `Vec::retain` preserve current value.
// Here we could probably use `Vec::push`
// but compiler currently fails to remove capacity check in `Vec::push`
// so this function became slower than `Vec::drain_filter`
// https://godbolt.org/z/7fhnnMh46
// And `Vec::push(x.assume_init_read())` is unsafe operation too anyway.
let old_len = res.len();
// Safety: We just allocated memory for this place.
let dst = res.as_mut_ptr().add(old_len);
// Safety: since we cannot panic until the end of closure
// and `Vec::retain` wouldn't panic and would remove `x`,
// making bitwise copy of `x` is safe.
x.as_ptr().copy_to_nonoverlapping(dst, 1);
// Safety: we just wrote additional value.
res.set_len(old_len + 1);
false
},
);
res
}
Benchmarks
Code of benchmarks is long so here link to the gist: https://gist.github.com/AngelicosPhosphoros/7ee482316bc1c83945f88308954e0d7e
It tries to split away odd numbers from they Vec using all three algorithms I listed.
Results:
algorithm
Mixed
Odds first
Evens first
sort-split
465us
35us
10us
drain_filter
26us
24us
22.5us
retain-uninit
17us
21us
19us
As you see, retain usage won in all cases except when sort-split doesn't actually have anything to do.
It is mainly because Vec::retain has been rigorously optimized over the years.
I want to build a HashSet<u8> from a Vec<u8>. I'd like to do this
in one line of code,
copying the data only once,
using only 2n memory,
but the only thing I can get to compile is this piece of .. junk, which I think copies the data twice and uses 3n memory.
fn vec_to_set(vec: Vec<u8>) -> HashSet<u8> {
let mut victim = vec.clone();
let x: HashSet<u8> = victim.drain(..).collect();
return x;
}
I was hoping to write something simple, like this:
fn vec_to_set(vec: Vec<u8>) -> HashSet<u8> {
return HashSet::from_iter(vec.iter());
}
but that won't compile:
error[E0308]: mismatched types
--> <anon>:5:12
|
5 | return HashSet::from_iter(vec.iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u8, found &u8
|
= note: expected type `std::collections::HashSet<u8>`
= note: found type `std::collections::HashSet<&u8, _>`
.. and I don't really understand the error message, probably because I need to RTFM.
Because the operation does not need to consume the vector¹, I think it should not consume it. That only leads to extra copying somewhere else in the program:
use std::collections::HashSet;
use std::iter::FromIterator;
fn hashset(data: &[u8]) -> HashSet<u8> {
HashSet::from_iter(data.iter().cloned())
}
Call it like hashset(&v) where v is a Vec<u8> or other thing that coerces to a slice.
There are of course more ways to write this, to be generic and all that, but this answer sticks to just introducing the thing I wanted to focus on.
¹This is based on that the element type u8 is Copy, i.e. it does not have ownership semantics.
The following should work nicely; it fulfills your requirements:
use std::collections::HashSet;
use std::iter::FromIterator;
fn vec_to_set(vec: Vec<u8>) -> HashSet<u8> {
HashSet::from_iter(vec)
}
from_iter() works on types implementing IntoIterator, so a Vec argument is sufficient.
Additional remarks:
you don't need to explicitly return function results; you only need to omit the semi-colon in the last expression in its body
I'm not sure which version of Rust you are using, but on current stable (1.12) to_iter() doesn't exist
Converting Vec to HashSet
Moving data ownership
let vec: Vec<u8> = vec![1, 2, 3, 4];
let hash_set: HashSet<u8> = vec.into_iter().collect();
Cloning data
let vec: Vec<u8> = vec![1, 2, 3, 4];
let hash_set: HashSet<u8> = vec.iter().cloned().collect();