Custom sorted Container - sorting

I'd like to have a container of points that are sorted by the distance to some point, which is given at runtime. In other languages, I could supply the container with a custom compare function, however, I understand this is not possible in rust.
Consider the following code problem:
/// distance between two points
fn distance(a: &(f32, f32), b: &(f32, f32)) -> f32 {
((a.0-b.0)*(a.0-b.0) + (a.1-b.1)*(a.1-b.1)).sqrt()
}
fn main() {
let origin = (1, 1); // assume values are provided at runtime
let mut container = BTreeSet::new(); // should be sorted by distance to origin
container.insert((1 ,9));
container.insert((2 ,2));
container.insert((1 ,5));
}
After the insertions I want the container to be sorted as [(2,2),(1,5),(1,9)]. The example uses BTreeSet, which I don't insist on using, but it feels like the closest to what I need.
I do NOT want a Vec that I have to resort manually after every insert().
So how do I connect distance(), origin, and container, preferably without third-party dependencies?

I don't think there is a good way to do this without storing the origin along with each point so that you can use it in the Cmp implementation.
use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::collections::BTreeSet;
#[derive(Debug, Clone, Copy)]
struct Point2D {
origin: (f32, f32),
point: (f32, f32),
}
impl Point2D {
fn length(self) -> f32 {
let (x1, y1) = self.origin;
let (x2, y2) = self.point;
((x1 - x2).powi(2) + (y1 - y2).powi(2)).sqrt()
}
}
impl PartialEq for Point2D {
fn eq(&self, rhs: &Self) -> bool {
self.origin == rhs.origin && self.length() == rhs.length()
}
}
impl Eq for Point2D {}
impl PartialOrd for Point2D {
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
(self.origin == rhs.origin).then_some(self.cmp(rhs))
}
}
impl Ord for Point2D {
fn cmp(&self, rhs: &Self) -> Ordering {
self.length().total_cmp(&rhs.length())
}
}
fn main() {
let origin = (1.0, 1.0); // assume values are provided at runtime
let mut container = BTreeSet::new(); // should be sorted by distance to origin
container.insert(Point2D {
origin,
point: (1.0, 9.0),
});
container.insert(Point2D {
origin,
point: (2.0, 2.0),
});
container.insert(Point2D {
origin,
point: (1.0, 5.0),
});
println!("{:?}", container.iter().map(|p| p.point).collect::<Vec<_>>());
// [(2.0, 2.0), (1.0, 5.0), (1.0, 9.0)]
}

Related

Trying to overlay images on top of each other

I am utilising a cargo lib called image = 0.23.14 where, I am trying to overlay the image on top of each other.
On their repository, there is an example where you can concat the images side by side.
use image::{
GenericImage,
GenericImageView,
ImageBuffer,
Pixel,
Primitive
};
fn h_concat<I, P, S>(images: &[I]) -> ImageBuffer<P, Vec<S>>
where
I: GenericImageView<Pixel = P>,
P: Pixel<Subpixel = S> + 'static,
S: Primitive + 'static {
let mut imgbuf = image::ImageBuffer::new(100, 100);
for img in images {
imgbuf.copy_from(img, 0, 0).unwrap();
}
imgbug
}
fn main() -> Result<()> {
h_concat(&[
image::open("images/img1.png").unwrap(),
image::open("images/img2.png").unwrap(),
]).save("random.png").unwrap();
Ok(())
}
I am wondering what if I want to append more files together.
Okay, after some fiddling and doing a bit more research on the documentation. I did found that there is a method image::imageops::overlay which solves my problem.
use image::{DynamicImage, imageops};
fn h_concat(mut base: DynamicImage, imgs: &[DynamicImage]) -> DynamicImage {
for img in imgs {
imageops::overlay(&mut base, img, 0, 0);
}
base
}
fn main() -> Result<()> {
let base = image::open("images/img1.png").unwrap();
h_concat(base, &[
image::open("images/img2.png").unwrap()
]).save("random.png").unwrap();
}

Initialize a vector of struct with zero values in Rust

I have a vector of struct and want to initialize it with all zeros.
struct MyStruct {
v1: u32,
v2: u64,
}
type MyVector = Vec<MyStruct>;
Cause the size of vector is already known, I can specify the capacity.
My first approach is as below,
impl Default for MyStruct {
fn default() -> Self {
Self {
v1: 0,
v2: 0,
}
}
}
fn init_my_vec() {
let size = 1000;
let mut my_vec: MyVector = Vec::with_capacity(size);
(0..size).for_each(|_| my_vec.push(MyStruct::default()))
}
As far as I know, the vector initialization with 0 is faster than using iterator. like this,
let usize_vec: Vec<usize> = vec![0; 1000];
// is faster than
let mut usize_vec: Vec<usize> = Vec::with_capacity(1000);
for i in 0..1000 {
usize_vec.push(0);
}
Question
Am I right about vector initialization speed? As fill with 0 is special instruction, using iterator is slower than using macro.
Is there any method that can initialize the vector of struct with 0 values safely and fast?
Or I should use unsafe code like making empty bytes and casting it to vector?
Speed measurement about Question 1
const VEC_SIZE: usize = 10_000;
fn init_with_iter() -> u128 {
let start = Instant::now();
let mut usize_vec: Vec<usize> = Vec::with_capacity(VEC_SIZE);
for i in 0..VEC_SIZE {
usize_vec.push(0);
}
start.elapsed().as_micros()
}
fn init_with_macro() -> u128 {
let start = Instant::now();
let _: Vec<usize> = vec![0; VEC_SIZE];
start.elapsed().as_micros()
}
Average time taken to generate vector 10,000 times is
using iter(init_with_iter): 514.6805 ms
using macro(init_with_macro): 2.0361 ms
on my machine
Speed measurement about Question 3
I think using unsafe function mem::zeroed is slightly faster than any others
const VEC_SIZE: usize = 10_000;
fn init_with_iter() -> u128 {
let start = Instant::now();
let mut my_vec: MyVector = Vec::with_capacity(VEC_SIZE);
for _ in 0..VEC_SIZE {
my_vec.push(MyStruct::default());
}
start.elapsed().as_micros()
}
fn init_with_macro() -> u128 {
let start = Instant::now();
let _: MyVector = vec![MyStruct::default(); VEC_SIZE];
start.elapsed().as_micros()
}
fn init_with_zeroed() -> u128 {
let start = Instant::now();
let _: MyVector = unsafe { vec![std::mem::zeroed(); VEC_SIZE] };
start.elapsed().as_micros()
}
Average time taken to generate vector 1,000 times is
using iter(init_with_iter): 575.572 ms.
using macro(init_with_macro): 486.958 ms
using unsafe function(init_with_zeroed): 468.885 ms
on my machine
Here is a criterion benchmark of your three approaches:
use criterion::{black_box, criterion_group, criterion_main, Criterion};
criterion_group!(
benches,
init_structs_with_iter,
init_structs_with_macro,
init_structs_with_unsafe
);
criterion_main!(benches);
const N_ITEMS: usize = 1000;
#[allow(unused)]
#[derive(Debug, Clone)]
struct MyStruct {
v1: u32,
v2: u64,
}
impl Default for MyStruct {
fn default() -> Self {
Self { v1: 0, v2: 0 }
}
}
fn init_structs_with_iter(c: &mut Criterion) {
c.bench_function("structs: with_iter", |b| {
b.iter(|| {
let mut my_vec = Vec::with_capacity(N_ITEMS);
(0..my_vec.capacity()).for_each(|_| my_vec.push(MyStruct::default()));
black_box(my_vec);
})
});
}
fn init_structs_with_macro(c: &mut Criterion) {
c.bench_function("structs: with_macro", |b| {
b.iter(|| {
let my_vec = vec![MyStruct::default(); N_ITEMS];
black_box(my_vec);
})
});
}
fn init_structs_with_unsafe(c: &mut Criterion) {
c.bench_function("structs: with_unsafe", |b| {
b.iter(|| {
let my_vec: Vec<MyStruct> = vec![unsafe { std::mem::zeroed() }; N_ITEMS];
black_box(my_vec);
})
});
}
And the results:
structs: with_iter time: [1.3857 us 1.3960 us 1.4073 us]
structs: with_macro time: [563.30 ns 565.30 ns 567.32 ns]
structs: with_unsafe time: [568.84 ns 570.09 ns 571.49 ns]
The vec![] macro seems to be the fastest (and also the cleanest and easiest to read).
As you can see, the time is measured in nanoseconds, so although the iterator version is 2-3x slower, it won't matter in practice. Optimizing the zero-initialization of a struct is the least important thing you can do - you can save at most 1 microsecond ;)
PS: those times include the memory allocation and deallocation times

How do I create a BinaryHeap that pops the smallest value, not the largest?

I can use the std::collections::BinaryHeap to iterate over a collection of a struct in the greatest to least order with pop, but my goal is to iterate over the collection from least to greatest.
I have succeeded by reversing the Ord implementation:
impl Ord for Item {
fn cmp(&self, other: &Self) -> Ordering {
match self.offset {
b if b > other.offset => Ordering::Less,
b if b < other.offset => Ordering::Greater,
b if b == other.offset => Ordering::Equal,
_ => Ordering::Equal, // ?not sure why compiler needs this
}
}
}
Now the BinaryHeap returns the Items in least to greatest. Seeing as how this is not the intended API, is this an incorrect or error prone pattern?
I realize that a LinkedList would give me the pop_front method, but I would need to sort the list on insert. Is that the better solution?
Reversing the order of a type inside the heap is fine. However, you don't need to implement your own order reversal. Instead, use std::cmp::Reverse or Ordering::reverse as appropriate.
If it makes sense for your type to actually be less than another value when some field is greater, implement your own Ord:
impl Ord for Item {
fn cmp(&self, other: &Self) -> Ordering {
self.offset.cmp(&other.offset).reverse()
}
}
If you do not wish to change the ordering of your type, flip the ordering when you put it in the BinaryHeap:
use std::{cmp::Reverse, collections::BinaryHeap};
fn main() {
let mut a: BinaryHeap<_> = vec![1, 2, 3].into_iter().collect();
if let Some(v) = a.pop() {
println!("Next is {}", v);
}
let mut b: BinaryHeap<_> = vec![1, 2, 3].into_iter().map(Reverse).collect();
if let Some(Reverse(v)) = b.pop() {
println!("Next is {}", v);
}
}
Next is 3
Next is 1
See also:
How can I implement a min-heap of f64 with Rust's BinaryHeap?
How do I select different std::cmp::Ord (or other trait) implementations for a given type?
Is [a LinkedList] the better solution?
99.9% of the time, a linked list is not a better solution.
For use std::cmp::Reverse
use std::cmp::Reverse;
use std::collections::BinaryHeap;
fn main() {
let mut heap = BinaryHeap::new();
(0..10)
.map(|i| {
if heap.len() >= 3 {
println!("Poped: {:?}.", heap.pop());
}
heap.push(Reverse(i));
})
.for_each(drop);
println!("{:?}", heap);
}
Poped: Some(Reverse(0)).
Poped: Some(Reverse(1)).
Poped: Some(Reverse(2)).
Poped: Some(Reverse(3)).
Poped: Some(Reverse(4)).
Poped: Some(Reverse(5)).
Poped: Some(Reverse(6)).
[Reverse(7), Reverse(8), Reverse(9)]
Rust Playground
For custom impl types:
use std::cmp::Ordering;
#[derive(Debug, PartialEq, Eq)]
struct MyU64Min(u64);
impl From<u64> for MyU64Min {
fn from(i: u64) -> Self {
Self(i)
}
}
impl PartialOrd for MyU64Min {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
other.0.partial_cmp(&self.0)
}
}
impl Ord for MyU64Min {
fn cmp(&self, other: &MyU64Min) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
fn main() {
let mut heap = BinaryHeap::new();
(0..10)
.map(|i| {
if heap.len() >= 3 {
println!("Poped: {:?}.", heap.pop());
}
heap.push(MyU64Min::from(i));
})
.for_each(drop);
println!("{:?}", heap);
}
Poped: Some(MyU64Min(0)).
Poped: Some(MyU64Min(1)).
Poped: Some(MyU64Min(2)).
Poped: Some(MyU64Min(3)).
Poped: Some(MyU64Min(4)).
Poped: Some(MyU64Min(5)).
Poped: Some(MyU64Min(6)).
[MyU64Min(7), MyU64Min(8), MyU64Min(9)]
Rust Playground

Rust traits: The bounds might not be implemented, and the traits I've implemented does not exist

So I've been trying to implement a library for vector and matrix maths, and I created some functions that worked alright but wanted to generalize for all number primitives and add the functionality into the normal operators.
My thought was that I'd create a container for a Vec<T>, that can contain either number types (like i32) or another container for Vec, so that matrices where possible. Ergo:
#[derive(Clone, Debug)]
struct Mat<T>(Vec<T>);
Then, to add together two vecs of any number I implement Add as:
impl<'a, T> Add for &'a Mat<T>
where T: PartialEq + PartialOrd + Add<T> + Sub<T> + Mul<T> + Div<T> + Rem<T> + Clone {
type Output = Option<Mat<<T as std::ops::Add>::Output>>;
fn add(self, other: &Mat<T>) -> Self::Output {
let a: &Vec<T> = self.pop();
let b: &Vec<T> = other.pop();
match a.len() == b.len() {
true => {
let mut retvec: Vec<<T as std::ops::Add>::Output> = Vec::new();
for i in 0..a.len() {
retvec.push(a[i].clone() + b[i].clone());
}
Some(Mat(retvec))
},
false => None
}
}
}
Edit: To further clarify, Mat::pop() is just the unwrap function, though probably poorly named.
The basic scenario of adding together two vectors of any number seems to work.
#[test]
fn add_override_vectors() {
let vec: Mat<i32> = Mat(vec![2, 2, 2]);
let newvec = &vec + &vec;
assert_eq!(*newvec.unwrap().pop(), vec![4,4,4]);
}
But matrices are giving me a headache. For them, the add function looks very similar, except for the let Some(x) statement:
impl<'a, T> Add for &'a Mat<Mat<T>>
where T: Add<&'a Mat<T>>{
type Output = Option<Mat<T>>;
fn add(self, other: &Mat<Mat<T>>) -> Self::Output {
let a: &Vec<Mat<T>> = self.pop();
let b: &Vec<Mat<T>> = other.pop();
match a.len() == b.len() {
true => {
let mut retvec: Vec<T> = Vec::new();
for i in 0..a.len() {
if let Some(x) = &a[i] + &b[i] {
retvec.push(x);
}
}
Some(Mat(retvec))
},
false => None
}
}
}
The error message I get is:
error[E0369]: binary operation `+` cannot be applied to type `&Mat<T>`
--> src\main.rs:46:38
|
46 | if let Some(x) = &a[i] + &b[i] {
| ^^^^^^^^^^^^^
|
= note: an implementation of `std::ops::Add` might be missing for `&Mat<T>`
So the compiler says that Add might not be implemented for &Mat<T>, but I thought that I've specified the bound so that it has that requirement in where T: Add<&'a Mat<T>. To me it seems that whatever is in &a[i] should have the Add trait implemented. What am I doing wrong here?
Just as extra clarification, my idea is that Add for &'a Mat<Mat<T>> should be able to be called recursively until it boils down to the Vec with an actual number type in it. Then the Add for &'a Mat<T> should be called.
There are two problems: the wrong associated Output type and the type of retvec
Something like that should work:
impl<'a, T> Add for &'a Mat<Mat<T>>
where
T: PartialEq + PartialOrd + Add<T> + Clone,
{
type Output = Option<Mat<Mat<<T as std::ops::Add>::Output>>>;
fn add(self, other: &Mat<Mat<T>>) -> Self::Output {
let a: &Vec<Mat<T>> = self.pop();
let b: &Vec<Mat<T>> = other.pop();
match a.len() == b.len() {
true => {
let mut retvec: Vec<Mat<<T as std::ops::Add>::Output>> = Vec::new();
for i in 0..a.len() {
if let Some(x) = &a[i] + &b[i] {
retvec.push(x);
}
}
Some(Mat(retvec))
}
false => None,
}
}
}
A part the compilation issue I think it is not correct to implement a trait for a "recursive" struct
like Mat<Mat<T>>, if you think X as type X = Mat<T> then the impl for Mat<T> suffices:
impl<'a, T> Add for &'a Mat<T>
where
T: PartialEq + PartialOrd + Add<T> + Clone
with the additional impl for Mat<T> values:
impl<T> Add for Mat<T>
where
T: PartialEq + PartialOrd + Add<T> + Clone
Below I post a full working code, please note that the Output type is no more an Option<Mat<T>> but a plain Mat<T> object:
this avoids a lot of headaches and probably it is conceptually wrong if you want to impl some type of algebra.
use std::ops::*;
use std::vec::Vec;
#[derive(Clone, Debug, PartialEq, PartialOrd)]
struct Mat<T>(Vec<T>);
impl<T> Mat<T> {
fn pop(&self) -> &Vec<T> {
&self.0
}
}
impl<T> Add for Mat<T>
where
T: PartialEq + PartialOrd + Add<T> + Clone,
{
type Output = Mat<<T as std::ops::Add>::Output>;
fn add(self, other: Mat<T>) -> Self::Output {
let a: &Vec<T> = self.pop();
let b: &Vec<T> = other.pop();
match a.len() == b.len() {
true => {
let mut retvec: Vec<<T as std::ops::Add>::Output> = Vec::new();
for i in 0..a.len() {
retvec.push(a[i].clone() + b[i].clone());
}
Mat(retvec)
}
false => Mat(Vec::new()),
}
}
}
impl<'a, T> Add for &'a Mat<T>
where
T: PartialEq + PartialOrd + Add<T> + Clone,
{
type Output = Mat<<T as std::ops::Add>::Output>;
fn add(self, other: &Mat<T>) -> Self::Output {
let a: &Vec<T> = self.pop();
let b: &Vec<T> = other.pop();
match a.len() == b.len() {
true => {
let mut retvec: Vec<<T as std::ops::Add>::Output> = Vec::new();
for i in 0..a.len() {
retvec.push(a[i].clone() + b[i].clone());
}
Mat(retvec)
}
false => Mat(Vec::new()),
}
}
}
#[test]
fn add_override_vectors() {
let vec: Mat<Mat<i32>> = Mat(vec![Mat(vec![2, 2, 2]), Mat(vec![3, 3, 3])]);
let newvec = &vec + &vec;
assert_eq!(*newvec.pop(), vec![Mat(vec![4, 4, 4]), Mat(vec![6, 6, 6])]);
}
#[test]
fn add_wrong_vectors() {
let vec1: Mat<Mat<i32>> = Mat(vec![Mat(vec![2, 2, 2]), Mat(vec![4, 4, 4])]);
let vec2: Mat<Mat<i32>> = Mat(vec![Mat(vec![3, 3, 3]), Mat(vec![3, 3])]);
let newvec = &vec1 + &vec2;
assert_eq!(*newvec.pop(), vec![Mat(vec![5, 5, 5]), Mat(vec![])]);
}
fn main() {
let vec: Mat<Mat<i32>> = Mat(vec![Mat(vec![1, 2, 2]), Mat(vec![3, 3, 3])]);
let newvec = &vec + &vec;
println!("Hello, world!: {:?}", newvec);
}
PS: Your Mat<T> type is not a matrix in the classical sense, perhaps another name should be more appropriate to avoid confusion.

I don't understand how borrowing works

I'm trying to write a kd-tree implementation, but I keep getting the error cannot move out of borrowed content.
This is my KDTree struct
pub struct KDTree {
pub bounding_box: Aabb,
pub axis: Option<Axis>,
left: Option<Box<KDTree>>,
right: Option<Box<KDTree>>,
pub objects: Option<Vec<Box<Geometry>>>,
}
This method, however, throws that error.
pub fn direct_samples(&self) -> Vec<u32> {
assert!(self.objects.is_some());
let mut direct_samples = Vec::new();
for (i, object) in self.objects
.expect("Expected tree to have objects")
.iter()
.enumerate() {
if object.material().emittance > 0f32 {
direct_samples.push(i as u32);
}
}
if self.left.is_some() {
direct_samples.extend(self.left.unwrap().direct_samples());
}
if self.right.is_some() {
direct_samples.extend(self.right.unwrap().direct_samples());
}
direct_samples
}
I understand that if I change the parameter to self instead of &self, it should work, but then when I call it, it gives the error use of moved value.
pub fn from_objects(objects: Vec<Box<Geometry>>) -> Scene {
let tree = KDTree::from_objects(objects);
Scene {
camera: Camera::new(),
objects: tree,
direct_samples: tree.direct_samples(),
}
}
Do I need to implement Copy on my KDTree? Won't this use a lot of cpu/memory to copy the entire thing?
The reason your code requires ownership of the KDTree is because you are calling Option::expect and Option::unwrap. The docs for these can be found here.
impl<T> Option<T> {
fn unwrap(self) -> T {
...
}
}
So when you are calling unwrap (or expect) the compiler rightly complains that you are taking the elements of your struct by value. To fix this, use the Option::as_ref method.
impl<T> Option<T> {
fn as_ref(&self) -> Option<&T> {
...
}
}
This will turn a reference to an option into an optional reference, which does not require ownership. You can see this in the signature of the function - it takes &self rather than self.
pub fn direct_samples(&self) -> Vec<u32> {
assert!(self.objects.is_some());
let mut direct_samples = Vec::new();
for (i, object) in self.objects.as_ref()
.expect("Expected tree to have objects")
.iter()
.enumerate() {
if object.material().emittance > 0f32 {
direct_samples.push(i as u32);
}
}
if self.left.is_some() {
direct_samples.extend(self.left.as_ref().unwrap().direct_samples());
}
if self.right.is_some() {
direct_samples.extend(self.right.as_ref().unwrap().direct_samples());
}
direct_samples
}
Do I need to implement Copy on my KDTree? Won't this use a lot of cpu/memory to copy the entire thing?
You can't implement Copy on your KDTree because it contains heap-allocated memory (boxes) - Copy means that your type can be copied just by copying its bytes, but that can't happen without invalidating single ownership in this case.

Resources