Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(wip): rkyv v0.8 #203

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ optional = true
default-features = false
features = ["alloc", "copy_unsafe", "size_64"]

[dependencies.rkyv_08]
package = "rkyv"
version = "0.8.9"
optional = true

[dependencies.serde]
version = "1"
optional = true
Expand Down Expand Up @@ -127,6 +132,7 @@ las = ["dep:las"]
serde = ["dep:serde", "serde/derive", "dep:serde_derive", "dep:serde_with", "fixed/serde", "aligned-vec/serde"]
simd = []
rkyv = ["dep:rkyv"]
rkyv_08 = ["dep:rkyv_08"]
test_utils = ["dep:rand", "dep:rand_chacha", "dep:rayon"]
tracing = ["dep:tracing", "dep:tracing-subscriber"]

Expand Down Expand Up @@ -215,6 +221,16 @@ name = "immutable-rkyv-deserialize"
path = "examples/immutable-rkyv-deserialize.rs"
required-features = ["rkyv"]

[[example]]
name = "immutable-rkyv_08-serialize"
path = "examples/immutable-rkyv_08-serialize.rs"
required-features = ["rkyv_08"]

[[example]]
name = "immutable-rkyv_08-deserialize"
path = "examples/immutable-rkyv_08-deserialize.rs"
required-features = ["rkyv_08"]

[[example]]
name = "pointcloud-las"
path = "examples/pointcloud-las.rs"
Expand Down
72 changes: 72 additions & 0 deletions examples/immutable-rkyv_08-deserialize.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use elapsed::ElapsedDuration;
use memmap::MmapOptions;
use std::error::Error;
use std::fs::File;
use std::time::Instant;
#[cfg(feature = "tracing")]
use tracing::Level;
#[cfg(feature = "tracing")]
use tracing_subscriber::fmt;

use rkyv_08::{from_bytes_unchecked, rancor::Error as RkyvError};

// use kiddo::immutable::float::kdtree::ArchivedImmutableKdTree;
use kiddo::immutable::float::kdtree::ImmutableKdTree;
use kiddo::SquaredEuclidean;

type Tree = ImmutableKdTree<f64, u32, 3, 256>;

fn main() -> Result<(), Box<dyn Error>>
where
{
#[cfg(feature = "tracing")]
let subscriber = fmt().with_max_level(Level::TRACE).without_time().finish();
#[cfg(feature = "tracing")]
tracing::subscriber::set_global_default(subscriber)?;

let query = [0.123f64, 0.456f64, 0.789f64];

let start = Instant::now();

// memmap the file into a buffer
let buf =
unsafe { MmapOptions::new().map(&File::open("./examples/immutable-test-tree-r08.rkyv")?)? };

// TODO: unsatisfied trait bounds when trying to call nearest_one on archived tree

// safe API
// let archived_tree = rkyv_08::access::<ArchivedImmutableKdTree<f64, u32, 3, 256>, RkyvError>(&buf[..]).unwrap();

// faster unsafe API
// let archived_tree =
// unsafe { rkyv_08::access_unchecked::<ArchivedImmutableKdTree<f64, u32, 3, 256>>(&buf) };

// perform a query
// let nearest_neighbour = archived_tree.nearest_one::<SquaredEuclidean>(&query);

// println!(
// "total elapsed: {}\n\n",
// ElapsedDuration::new(start.elapsed())
// );
// println!(
// "Nearest item to query (archived): {:?}",
// nearest_neighbour.item
// );

// full deserialization
let tree = unsafe { from_bytes_unchecked::<Tree, RkyvError>(&buf) }?;

// perform a query
let nearest_neighbour = tree.nearest_one::<SquaredEuclidean>(&query);

println!(
"Nearest item to query (deserialized): {:?}",
nearest_neighbour.item
);
println!(
"total elapsed: {}\n\n",
ElapsedDuration::new(start.elapsed())
);

Ok(())
}
63 changes: 63 additions & 0 deletions examples/immutable-rkyv_08-serialize.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use elapsed::ElapsedDuration;
// use memmap::MmapOptions;
use rand::Rng;
use rand_chacha::rand_core::SeedableRng;
use rkyv_08::{rancor::Error as RkyvError, to_bytes};
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::time::Instant;
#[cfg(feature = "tracing")]
use tracing::Level;
#[cfg(feature = "tracing")]
use tracing_subscriber::fmt;
use ubyte::ToByteUnit;

use kiddo::float::distance::SquaredEuclidean;
use kiddo::immutable::float::kdtree::ImmutableKdTree;

const NUM_ITEMS: usize = 50_000_000;

type Tree = ImmutableKdTree<f64, u32, 3, 256>;

fn main() -> Result<(), Box<dyn Error>> {
#[cfg(feature = "tracing")]
let subscriber = fmt().with_max_level(Level::TRACE).without_time().finish();
#[cfg(feature = "tracing")]
tracing::subscriber::set_global_default(subscriber)?;

let query = [0.123f64, 0.456f64, 0.789f64];

// build and serialize a large ImmutableKdTree
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1);
let content_to_add: Vec<[f64; 3]> = (0..NUM_ITEMS).map(|_| rng.gen::<[f64; 3]>()).collect();

let start = Instant::now();
let tree: Tree = ImmutableKdTree::new_from_slice(&content_to_add);
println!(
"Populated ImmutableKdTree with {} items ({})",
tree.size(),
ElapsedDuration::new(start.elapsed())
);

let nearest_neighbour = tree.nearest_one::<SquaredEuclidean>(&query);

println!("Nearest item to query: {:?}", nearest_neighbour.item);

let start = Instant::now();

let buf = to_bytes::<RkyvError>(&tree)?;

let mut file = File::create("./examples/immutable-test-tree-r08.rkyv")?;
file.write_all(&buf)
.expect("Could not write serialized rkyv to file");

let file_size = file.metadata().unwrap().len().bytes();
println!(
"Serialized k-d tree to rkyv file 'immutable-test-tree-r08.rkyv' ({}). File size: {:.2}",
ElapsedDuration::new(start.elapsed()),
file_size
);

Ok(())
}
2 changes: 1 addition & 1 deletion src/immutable/common/generate_immutable_nearest_one.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ macro_rules! generate_immutable_nearest_one {
use cmov::Cmov;
use $crate::modified_van_emde_boas::modified_van_emde_boas_get_child_idx_v2_branchless;

if level > self.max_stem_level {
if level > Into::<i32>::into(self.max_stem_level) || self.stems.is_empty() {
self.search_leaf_for_nearest_one::<D>(query, nearest, leaf_idx as usize);
return;
}
Expand Down
54 changes: 47 additions & 7 deletions src/immutable/float/kdtree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@
//! As with the vanilla tree, [`f64`] or [`f32`] are supported currently for co-ordinate
//! values, or [`f16`](https://docs.rs/half/latest/half/struct.f16.html) if the `f16` feature is enabled

pub use crate::float::kdtree::Axis;
use crate::float_leaf_slice::leaf_slice::{LeafSlice, LeafSliceFloat, LeafSliceFloatChunk};
#[cfg(feature = "modified_van_emde_boas")]
use crate::modified_van_emde_boas::modified_van_emde_boas_get_child_idx_v2_branchless;
use crate::traits::Content;
use std::{cmp::PartialEq, fmt::Debug};

use aligned_vec::{avec, AVec, ConstAlign, CACHELINE_ALIGN};
use array_init::array_init;
use az::{Az, Cast};
Expand All @@ -25,8 +22,14 @@ use ordered_float::OrderedFloat;
use rkyv::vec::ArchivedVec;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::cmp::PartialEq;
use std::fmt::Debug;

pub use crate::float::kdtree::Axis;
use crate::float_leaf_slice::leaf_slice::{LeafSlice, LeafSliceFloat, LeafSliceFloatChunk};
#[cfg(feature = "rkyv_08")]
use crate::immutable::float::rkyv_aligned_vec::EncodeAVec;
#[cfg(feature = "modified_van_emde_boas")]
use crate::modified_van_emde_boas::modified_van_emde_boas_get_child_idx_v2_branchless;
use crate::traits::Content;

/// Immutable floating point k-d tree
///
Expand All @@ -45,8 +48,14 @@ use std::fmt::Debug;
///
/// A convenient type alias exists for ImmutableKdTree with some sensible defaults set: [`kiddo::ImmutableKdTree`](`crate::ImmutableKdTree`).
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "rkyv_08",
derive(rkyv_08::Archive, rkyv_08::Serialize, rkyv_08::Deserialize)
)]
#[cfg_attr(feature = "rkyv_08", rkyv(crate=rkyv_08))]
#[derive(Clone, Debug, PartialEq)]
pub struct ImmutableKdTree<A: Copy + Default, T: Copy + Default, const K: usize, const B: usize> {
#[cfg_attr(feature = "rkyv_08", rkyv(with = EncodeAVec<A>))]
pub(crate) stems: AVec<A>,

#[cfg_attr(feature = "serde", serde(with = "crate::custom_serde::array_of_vecs"))]
Expand Down Expand Up @@ -212,6 +221,37 @@ where
}
}

#[cfg(feature = "rkyv_08")]
impl<A, T, const K: usize, const B: usize> ArchivedImmutableKdTree<A, T, K, B>
where
A: Axis + LeafSliceFloat<T> + LeafSliceFloatChunk<T, K> + rkyv_08::Archive<Archived = A>,
T: Content + rkyv_08::Archive<Archived = T>,
usize: Cast<T>,
{
/// Returns the current number of elements stored in the tree
#[inline]
pub fn size(&self) -> usize {
self.leaf_items.len()
}

/// Returns a LeafSlice for a given leaf index
#[inline]
pub(crate) fn get_leaf_slice(&self, leaf_idx: usize) -> LeafSlice<A, T, K> {
let extents = unsafe { self.leaf_extents.get_unchecked(leaf_idx) };
let start = Into::<u32>::into(extents.0) as usize;
let end = Into::<u32>::into(extents.1) as usize;

// Artificially extend size to be at least chunk length for faster processing
// TODO: why does this slow things down?
// let end = end.max(start + 32).min(self.leaf_items.len() as u32);

LeafSlice::new(
array_init::array_init(|i| &self.leaf_points[i][start..end]),
&self.leaf_items[start..end],
)
}
}

impl<A: Axis, T: Content, const K: usize, const B: usize> From<&[[A; K]]>
for ImmutableKdTree<A, T, K, B>
where
Expand Down
3 changes: 3 additions & 0 deletions src/immutable/float/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@
pub mod kdtree;
#[doc(hidden)]
pub mod query;

#[cfg(feature = "rkyv_08")]
mod rkyv_aligned_vec;
20 changes: 20 additions & 0 deletions src/immutable/float/query/nearest_one.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,26 @@ where
);
}

#[cfg(feature = "rkyv_08")]
use crate::immutable::float::kdtree::ArchivedImmutableKdTree;
#[cfg(feature = "rkyv_08")]
impl<A, T, const K: usize, const B: usize> ArchivedImmutableKdTree<A, T, K, B>
where
A: Axis + LeafSliceFloat<T> + LeafSliceFloatChunk<T, K> + rkyv_08::Archive<Archived = A>,
T: Content + rkyv_08::Archive<Archived = T>,
usize: Cast<T>,
{
generate_immutable_float_nearest_one!(
"use std::fs::File;
use memmap::MmapOptions;

use kiddo::immutable::float::kdtree::AlignedArchivedImmutableKdTree;

let mmap = unsafe { MmapOptions::new().map(&File::open(\"./examples/immutable-doctest-tree.rkyv\").unwrap()).unwrap() };
let tree = unsafe { access_unchecked::<Archived<ImmutableKdTree<f64, u32, 3, 256>>>(&buf) };"
);
}

#[cfg(test)]
mod tests {
use crate::float::distance::SquaredEuclidean;
Expand Down
Loading
Loading