From ad16bd85be7e7c6b9bb5bf363f9259756fe7760d Mon Sep 17 00:00:00 2001 From: Tamo Date: Wed, 28 May 2025 11:39:59 +0200 Subject: [PATCH 01/24] Remove a first batch of useless writes to tmp files and LMDB --- src/node.rs | 9 +++- src/writer.rs | 133 ++++++++++++++++++++++---------------------------- 2 files changed, 65 insertions(+), 77 deletions(-) diff --git a/src/node.rs b/src/node.rs index 18c9c37..b792062 100644 --- a/src/node.rs +++ b/src/node.rs @@ -40,8 +40,15 @@ impl<'a, D: Distance> Node<'a, D> { None } } -} + pub fn descendants(self) -> Option> { + if let Node::Descendants(descendants) = self { + Some(descendants) + } else { + None + } + } +} /// A leaf node which corresponds to the vector inputed /// by the user and the distance header. pub struct Leaf<'a, D: Distance> { diff --git a/src/writer.rs b/src/writer.rs index c879572..e8f3fb9 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use heed::types::{Bytes, DecodeIgnore, Unit}; use heed::{MdbError, PutFlags, RoTxn, RwTxn}; +use nohash::{BuildNoHashHasher, IntMap}; use rand::{Rng, SeedableRng}; use rayon::iter::repeatn; use rayon::prelude::*; @@ -17,7 +18,6 @@ use crate::item_iter::ItemIter; use crate::node::{Descendants, ItemIds, Leaf, SplitPlaneNormal}; use crate::parallel::{ ConcurrentNodeIds, ImmutableLeafs, ImmutableSubsetLeafs, ImmutableTrees, TmpNodes, - TmpNodesReader, }; use crate::reader::item_leaf; use crate::unaligned_vector::UnalignedVector; @@ -669,22 +669,23 @@ impl Writer { nb_tree_nodes: u64, concurrent_node_ids: &ConcurrentNodeIds, ) -> Result { - let mut large_descendants = RoaringBitmap::new(); - if roots.is_empty() { - return Ok(large_descendants); + return Ok(RoaringBitmap::new()); } + // If we have only one roots it means we're splitting a large descendants. + // Otherwise it means we're updating the whole database and will need all the tree nodes. + let immutable_tree_nodes = if roots.len() == 1 { + ImmutableTrees::sub_tree_from_id(wtxn, self.database, self.index, roots[0])? + } else { + ImmutableTrees::new(wtxn, self.database, self.index, nb_tree_nodes)? + }; + let mut descendants_to_update: IntMap = + IntMap::with_hasher(BuildNoHashHasher::default()); + while !to_insert.is_empty() { options.cancelled()?; - // If we have only one roots it means we're splitting a large descendants. - // Otherwise it means we're updating the whole database and will need all the tree nodes. - let immutable_tree_nodes = if roots.len() == 1 { - ImmutableTrees::sub_tree_from_id(wtxn, self.database, self.index, roots[0])? - } else { - ImmutableTrees::new(wtxn, self.database, self.index, nb_tree_nodes)? - }; let (leafs, to_insert) = ImmutableLeafs::new( wtxn, self.database, @@ -699,22 +700,30 @@ impl Writer { FrozzenReader { leafs: &leafs, trees: &immutable_tree_nodes, concurrent_node_ids }; let tmp_descendant_to_write = self.insert_items_in_tree(options, rng, roots, &to_insert, &frozzen_reader)?; + for (item_id, descendants) in tmp_descendant_to_write.into_iter() { + descendants_to_update.entry(item_id).or_default().extend(descendants.clone()); + } + } - for (tmp_node, descendants) in tmp_descendant_to_write.iter() { - large_descendants |= descendants; + let mut large_descendants = RoaringBitmap::new(); - for item_id in tmp_node.to_delete() { - options.cancelled()?; - let key = Key::tree(self.index, item_id); - self.database.remap_data_type::().delete(wtxn, &key)?; - } - for (item_id, item_bytes) in tmp_node.to_insert() { - options.cancelled()?; - let key = Key::tree(self.index, item_id); - self.database.remap_data_type::().put(wtxn, &key, item_bytes)?; - } + for (item_id, descendants) in descendants_to_update.into_iter() { + options.cancelled()?; + + let key = Key::tree(self.index, item_id); + let old_node = self.database.get(&wtxn, &key)?.unwrap(); + let Descendants { descendants: original_descendants } = old_node.descendants().unwrap(); + let new_descendants = original_descendants.into_owned() | descendants; + self.database.put( + wtxn, + &key, + &Node::Descendants(Descendants { descendants: Cow::Borrowed(&new_descendants) }), + )?; + if !self.fit_in_descendant(options, new_descendants.len()) { + large_descendants.insert(item_id); } } + Ok(large_descendants) } @@ -938,32 +947,38 @@ impl Writer { roots: &[ItemId], to_insert: &RoaringBitmap, frozen_reader: &FrozzenReader, - ) -> Result> { + ) -> Result> { repeatn(rng.next_u64(), roots.len()) .zip(roots) .map(|(seed, root)| { opt.cancelled()?; tracing::debug!("started updating tree {root:X}..."); let mut rng = R::seed_from_u64(seed.wrapping_add(*root as u64)); - let mut tmp_descendant: TmpNodes> = match self.tmpdir.as_ref() { - Some(path) => TmpNodes::new_in(path)?, - None => TmpNodes::new()?, - }; - let mut large_descendants = RoaringBitmap::new(); + let mut descendants_to_update = IntMap::with_hasher(BuildNoHashHasher::default()); self.insert_items_in_file( opt, frozen_reader, &mut rng, *root, to_insert, - &mut large_descendants, - &mut tmp_descendant, + &mut descendants_to_update, )?; tracing::debug!("finished updating tree {root:X}"); - Ok((tmp_descendant.into_bytes_reader()?, large_descendants)) + Ok(descendants_to_update) }) - .collect() + .reduce( + || Ok(IntMap::with_hasher(BuildNoHashHasher::default())), + |acc, descendants_to_update| match (acc, descendants_to_update) { + (Err(e), _) | (_, Err(e)) => Err(e), + (Ok(mut acc), Ok(descendants_to_update)) => { + for (item_id, descendants) in descendants_to_update.into_iter() { + acc.entry(item_id).or_default().extend(descendants.clone()); + } + Ok(acc) + } + }, + ) } /// Find all the descendants that matches the list of items to insert and write them to a file @@ -975,32 +990,13 @@ impl Writer { rng: &mut R, current_node: ItemId, to_insert: &RoaringBitmap, - large_descendants: &mut RoaringBitmap, - tmp_nodes: &mut TmpNodes>, - ) -> Result { + descendants_to_update: &mut IntMap, + ) -> Result<()> { opt.cancelled()?; match frozen_reader.trees.get(current_node)?.unwrap() { Node::Leaf(_) => unreachable!(), - Node::Descendants(Descendants { descendants }) => { - let mut new_descendants = descendants.clone().into_owned(); - // insert all of our IDs in the descendants - new_descendants |= to_insert; - - if !self.fit_in_descendant(opt, new_descendants.len()) { - large_descendants.insert(current_node); - } - - // If the number of descendant changed it means we inserted new items and must overwrite the node - if descendants.len() != new_descendants.len() { - // otherwise we can just update our descendants - tmp_nodes.put( - current_node, - &Node::Descendants(Descendants { - descendants: Cow::Owned(new_descendants.clone()), - }), - )?; - } - Ok(current_node) + Node::Descendants(Descendants { descendants: _ }) => { + descendants_to_update.insert(current_node, to_insert.clone()); } Node::SplitPlaneNormal(SplitPlaneNormal { normal, left, right }) => { // Split the to_insert into two bitmaps on the left and right of this normal @@ -1022,40 +1018,25 @@ impl Writer { } } - let new_left = self.insert_items_in_file( + self.insert_items_in_file( opt, frozen_reader, rng, left, &left_ids, - large_descendants, - tmp_nodes, + descendants_to_update, )?; - let new_right = self.insert_items_in_file( + self.insert_items_in_file( opt, frozen_reader, rng, right, &right_ids, - large_descendants, - tmp_nodes, + descendants_to_update, )?; - - if new_left != left || new_right != right { - tmp_nodes.put( - current_node, - &Node::SplitPlaneNormal(SplitPlaneNormal { - normal, - left: new_left, - right: new_right, - }), - )?; - Ok(current_node) - } else { - Ok(current_node) - } } } + Ok(()) } /// Creates a tree of nodes from the frozzen items that lives From e9d2c646a7e3c51a31475295bf8ab4bc6fd6160a Mon Sep 17 00:00:00 2001 From: Tamo Date: Wed, 28 May 2025 16:18:28 +0200 Subject: [PATCH 02/24] update the tmp_nodes to be readable --- src/node.rs | 24 +++++++++ src/parallel.rs | 108 ++++++++++++++++++++++++++++++++++++----- src/tests/mod.rs | 1 + src/tests/tmp_nodes.rs | 101 ++++++++++++++++++++++++++++++++++++++ src/writer.rs | 6 +-- 5 files changed, 226 insertions(+), 14 deletions(-) create mode 100644 src/tests/tmp_nodes.rs diff --git a/src/node.rs b/src/node.rs index b792062..c855a62 100644 --- a/src/node.rs +++ b/src/node.rs @@ -19,6 +19,20 @@ pub enum Node<'a, D: Distance> { SplitPlaneNormal(SplitPlaneNormal<'a, D>), } +impl<'a, D: Distance> Node<'a, D> { + pub fn to_owned(self) -> Node<'static, D> { + match self { + Node::Leaf(leaf) => Node::Leaf(leaf.into_owned()), + Node::Descendants(descendants) => Node::Descendants(Descendants { + descendants: Cow::Owned(descendants.descendants.into_owned()), + }), + Node::SplitPlaneNormal(split_plane_normal) => { + Node::SplitPlaneNormal(split_plane_normal.into_owned()) + } + } + } +} + /// A node generic over the version of the database. /// Should only be used while reading from the database. #[derive(Clone, Debug)] @@ -149,6 +163,16 @@ impl fmt::Debug for SplitPlaneNormal<'_, D> { } } +impl SplitPlaneNormal<'_, D> { + pub fn into_owned(self) -> SplitPlaneNormal<'static, D> { + SplitPlaneNormal { + left: self.left, + right: self.right, + normal: self.normal.map(|normal| Cow::Owned(normal.into_owned())), + } + } +} + impl Clone for SplitPlaneNormal<'_, D> { fn clone(&self) -> Self { Self { left: self.left, right: self.right, normal: self.normal.clone() } diff --git a/src/parallel.rs b/src/parallel.rs index 8bf8936..3e4a754 100644 --- a/src/parallel.rs +++ b/src/parallel.rs @@ -1,6 +1,6 @@ use core::slice; use std::fs::File; -use std::io::{BufWriter, Write}; +use std::io::{BufReader, BufWriter, Read, Seek, SeekFrom, Write}; use std::marker; use std::path::Path; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering}; @@ -18,9 +18,81 @@ use crate::key::{Key, Prefix, PrefixCodec}; use crate::node::{Node, SplitPlaneNormal}; use crate::{Database, Distance, Error, ItemId, Result}; +#[derive(Default, Debug)] +enum TmpNodesState { + Writing(BufWriter), + Reading(BufReader), + // Ugly trick because otherwise I can't take the value out of the enum. Can we do better? + // The enum should never be let in this state. + #[default] + Invalid, +} + +impl TmpNodesState { + pub fn write_all(&mut self, bytes: &[u8]) -> Result<()> { + let this = match std::mem::take(self) { + TmpNodesState::Writing(mut writer) => { + writer.write_all(bytes)?; + TmpNodesState::Writing(writer) + } + TmpNodesState::Reading(reader) => { + let mut writer = BufWriter::new(reader.into_inner()); + writer.write_all(bytes)?; + TmpNodesState::Writing(writer) + } + TmpNodesState::Invalid => unreachable!(), + }; + + debug_assert!(!matches!(this, TmpNodesState::Invalid)); + + *self = this; + Ok(()) + } + + pub fn read_all(&mut self, (start, end): (usize, usize)) -> Result> { + debug_assert!(start < end); + let mut buffer = vec![0; end - start]; + + let this = match std::mem::take(self) { + TmpNodesState::Writing(mut writer) => { + writer.flush()?; + let mut reader = BufReader::new(writer.into_inner().expect("Could not convert the writer to a file even thought it was flushed right before")); + reader.seek(SeekFrom::Start(start as u64))?; + reader.read_exact(&mut buffer)?; + TmpNodesState::Reading(reader) + } + TmpNodesState::Reading(mut reader) => { + reader.seek(SeekFrom::Start(start as u64))?; + reader.read_exact(&mut buffer)?; + TmpNodesState::Reading(reader) + } + TmpNodesState::Invalid => unreachable!(), + }; + + debug_assert!(!matches!(this, TmpNodesState::Invalid)); + + *self = this; + Ok(buffer) + } + + pub fn into_inner(self) -> Result { + let file = match self { + TmpNodesState::Writing(mut writer) => { + writer.flush()?; + writer.into_inner().expect("Could not convert the writer to a file even thought it was flushed right before") + } + TmpNodesState::Reading(reader) => reader.into_inner(), + TmpNodesState::Invalid => unreachable!(), + }; + Ok(file) + } +} + /// A structure to store the tree nodes out of the heed database. +/// You should avoid alternating between writing and reading as it flushes the file on each operation and lose the read buffer. +/// The structure is optimized for reading the last written nodes. pub struct TmpNodes { - file: BufWriter, + file: TmpNodesState, ids: Vec, bounds: Vec, deleted: RoaringBitmap, @@ -28,11 +100,11 @@ pub struct TmpNodes { _marker: marker::PhantomData, } -impl<'a, DE: BytesEncode<'a>> TmpNodes { +impl<'a, D: Distance> TmpNodes { /// Creates an empty `TmpNodes`. - pub fn new() -> heed::Result> { + pub fn new() -> heed::Result> { Ok(TmpNodes { - file: tempfile::tempfile().map(BufWriter::new)?, + file: TmpNodesState::Writing(tempfile::tempfile().map(BufWriter::new)?), ids: Vec::new(), bounds: vec![0], deleted: RoaringBitmap::new(), @@ -42,9 +114,9 @@ impl<'a, DE: BytesEncode<'a>> TmpNodes { } /// Creates an empty `TmpNodes` in the defined folder. - pub fn new_in(path: &Path) -> heed::Result> { + pub fn new_in(path: &Path) -> heed::Result> { Ok(TmpNodes { - file: tempfile::tempfile_in(path).map(BufWriter::new)?, + file: TmpNodesState::Writing(tempfile::tempfile_in(path).map(BufWriter::new)?), ids: Vec::new(), bounds: vec![0], deleted: RoaringBitmap::new(), @@ -59,10 +131,10 @@ impl<'a, DE: BytesEncode<'a>> TmpNodes { // TODO move that in the type &mut self, item: ItemId, - data: &'a DE::EItem, - ) -> heed::Result<()> { + data: &'a Node, + ) -> Result<()> { assert!(item != ItemId::MAX); - let bytes = DE::bytes_encode(data).map_err(heed::Error::Encoding)?; + let bytes = NodeCodec::bytes_encode(data).map_err(heed::Error::Encoding)?; self.file.write_all(&bytes)?; let last_bound = self.bounds.last().unwrap(); self.bounds.push(last_bound + bytes.len()); @@ -74,6 +146,20 @@ impl<'a, DE: BytesEncode<'a>> TmpNodes { Ok(()) } + /// Get the node at the given item id. + /// Ignore the remapped ids and deletions, only suitable when appending to the file. + /// A flush will be executed on the file if the previous operation was a write. + pub fn get(&mut self, item: ItemId) -> Result>> { + // In our current implementation, when we starts retrieving the nodes, it's always the nodes of the last tree, + // so it makes sense to search in reverse order. + let Some(position) = self.ids.iter().rev().position(|id| *id == item) else { + return Ok(None); + }; + let bounds = &self.bounds[self.bounds.len() - position - 2..self.bounds.len() - position]; + let bytes = self.file.read_all((bounds[0], bounds[1]))?; + Ok(Some(NodeCodec::bytes_decode(&bytes).map_err(heed::Error::Decoding)?.to_owned())) + } + /// Remap the item id of an already inserted node to another node. /// /// Only applies to the nodes to insert. It won't interact with the to_delete nodes. @@ -91,7 +177,7 @@ impl<'a, DE: BytesEncode<'a>> TmpNodes { /// Converts it into a readers to read the nodes. pub fn into_bytes_reader(self) -> Result { - let file = self.file.into_inner().map_err(|iie| iie.into_error())?; + let file = self.file.into_inner()?; // safety: No one should move our files around let mmap = unsafe { Mmap::map(&file)? }; #[cfg(unix)] diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 55e1830..a0b0efd 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -13,6 +13,7 @@ use crate::{Database, Distance, MetadataCodec, NodeCodec, NodeMode, Reader}; mod binary_quantized; mod reader; +mod tmp_nodes; mod upgrade; mod writer; diff --git a/src/tests/tmp_nodes.rs b/src/tests/tmp_nodes.rs new file mode 100644 index 0000000..3afad97 --- /dev/null +++ b/src/tests/tmp_nodes.rs @@ -0,0 +1,101 @@ +use std::borrow::Cow; + +use insta::assert_debug_snapshot; +use roaring::RoaringBitmap; + +use crate::{ + distance::Cosine, + internals::UnalignedVector, + node::{Descendants, Node, SplitPlaneNormal}, + parallel::TmpNodes, +}; + +#[test] +fn test_put_and_get_tmp_nodes() { + let mut tmp_nodes = TmpNodes::::new().unwrap(); + for i in 0..10 { + let node = Node::Descendants(Descendants { + descendants: Cow::Owned(RoaringBitmap::from_iter(&[i + 0, i + 1, i + 2])), + }); + tmp_nodes.put(i, &node).unwrap(); + } + + assert_debug_snapshot!(tmp_nodes.get(0).unwrap().unwrap(), @r" + Descendants( + Descendants { + descendants: [ + 0, + 1, + 2, + ], + }, + ) + "); + assert_debug_snapshot!(tmp_nodes.get(9).unwrap().unwrap(), @r" + Descendants( + Descendants { + descendants: [ + 9, + 10, + 11, + ], + }, + ) + "); + assert_debug_snapshot!(tmp_nodes.get(10).unwrap(), @"None"); + + // We start at 11 so there will be a hole at the id 10 + for i in 11..20 { + let normal = + if i % 2 == 0 { Some(UnalignedVector::from_vec(vec![i as f32])) } else { None }; + let node = + Node::SplitPlaneNormal(SplitPlaneNormal { left: i * 2, right: i * 2 + 1, normal }); + tmp_nodes.put(i, &node).unwrap(); + } + + assert_debug_snapshot!(tmp_nodes.get(10).unwrap(), @"None"); + assert_debug_snapshot!(tmp_nodes.get(11).unwrap().unwrap(), @r#" + SplitPlaneNormal( + SplitPlaneNormal { + left: 22, + right: 23, + normal: "none", + }, + ) + "#); + + assert_debug_snapshot!(tmp_nodes.get(15).unwrap().unwrap(), @r#" + SplitPlaneNormal( + SplitPlaneNormal { + left: 30, + right: 31, + normal: "none", + }, + ) + "#); + + assert_debug_snapshot!(tmp_nodes.get(19).unwrap().unwrap(), @r#" + SplitPlaneNormal( + SplitPlaneNormal { + left: 38, + right: 39, + normal: "none", + }, + ) + "#); + + assert_debug_snapshot!(tmp_nodes.get(20).unwrap(), @"None"); + + // can we still get the previous nodes correctly? + assert_debug_snapshot!(tmp_nodes.get(3).unwrap().unwrap(), @r" + Descendants( + Descendants { + descendants: [ + 3, + 4, + 5, + ], + }, + ) + "); +} diff --git a/src/writer.rs b/src/writer.rs index e8f3fb9..2f656a9 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -826,7 +826,7 @@ impl Writer { sub: None, }); - let mut tmp_nodes: TmpNodes> = match self.tmpdir.as_ref() { + let mut tmp_nodes: TmpNodes = match self.tmpdir.as_ref() { Some(path) => TmpNodes::new_in(path)?, None => TmpNodes::new()?, }; @@ -861,7 +861,7 @@ impl Writer { options: &BuildOption, rtxn: &RoTxn, current_node: ItemId, - tmp_nodes: &mut TmpNodes>, + tmp_nodes: &mut TmpNodes, to_delete: &RoaringBitmap, ) -> Result<(ItemId, RoaringBitmap)> { options.cancelled()?; @@ -1049,7 +1049,7 @@ impl Writer { reader: &FrozzenReader, rng: &mut R, item_indices: &RoaringBitmap, - tmp_nodes: &mut TmpNodes>, + tmp_nodes: &mut TmpNodes, ) -> Result<(ItemId, u64)> { opt.cancelled()?; if self.fit_in_descendant(opt, item_indices.len()) { From 20b891e4af6670708732f01f91b198f01d541234 Mon Sep 17 00:00:00 2001 From: Tamo Date: Tue, 10 Jun 2025 19:00:38 +0200 Subject: [PATCH 03/24] Parallelize the split of large descendants --- Cargo.toml | 1 + src/distance/mod.rs | 4 + src/parallel.rs | 64 ++- src/tests/reader.rs | 5 +- ...ite_and_update_lot_of_random_points-2.snap | 306 +++++++------- ...write_and_update_lot_of_random_points.snap | 206 +++++----- src/tests/writer.rs | 120 +++--- src/unaligned_vector/binary_quantized.rs | 4 + src/unaligned_vector/f32.rs | 4 + src/unaligned_vector/mod.rs | 3 + src/writer.rs | 381 +++++++++++------- 11 files changed, 603 insertions(+), 495 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c5af697..0b3d24e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ thiserror = "2.0.9" nohash = "0.2.0" page_size = "0.6.0" enum-iterator = "2.1.0" +thread_local = "1.1.8" [dev-dependencies] anyhow = "1.0.95" diff --git a/src/distance/mod.rs b/src/distance/mod.rs index 5ac4f21..b13bf36 100644 --- a/src/distance/mod.rs +++ b/src/distance/mod.rs @@ -131,6 +131,10 @@ pub trait Distance: Send + Sync + Sized + Clone + fmt::Debug + 'static { ) -> heed::Result<()> { Ok(()) } + + fn size_of_item(dimensions: usize) -> usize { + std::mem::size_of::() + Self::VectorCodec::size_of_item(dimensions) + } } fn two_means( diff --git a/src/parallel.rs b/src/parallel.rs index 3e4a754..55bc309 100644 --- a/src/parallel.rs +++ b/src/parallel.rs @@ -15,7 +15,7 @@ use roaring::{RoaringBitmap, RoaringTreemap}; use crate::internals::{KeyCodec, Leaf, NodeCodec}; use crate::key::{Key, Prefix, PrefixCodec}; -use crate::node::{Node, SplitPlaneNormal}; +use crate::node::Node; use crate::{Database, Distance, Error, ItemId, Result}; #[derive(Default, Debug)] @@ -288,9 +288,35 @@ pub struct ImmutableLeafs<'t, D> { impl<'t, D: Distance> ImmutableLeafs<'t, D> { /// Creates the structure by fetching all the leaf pointers /// and keeping the transaction making the pointers valid. + pub fn new( + rtxn: &'t RoTxn, + database: Database, + items: &RoaringBitmap, + index: u16, + ) -> heed::Result { + let mut leafs = IntMap::with_capacity_and_hasher( + items.len() as usize, + BuildNoHashHasher::default(), + ); + let mut constant_length = None; + + for item_id in items { + let bytes = + database.remap_data_type::().get(rtxn, &Key::item(index, item_id))?.unwrap(); + assert_eq!(*constant_length.get_or_insert(bytes.len()), bytes.len()); + + let ptr = bytes.as_ptr(); + leafs.insert(item_id, ptr); + } + + Ok(ImmutableLeafs { leafs, constant_length, _marker: marker::PhantomData }) + } + + /// Creates the structure by fetching all the leaf pointers + /// and keeping the transaction making the pointers valid. /// Do not take more items than memory allows. /// Remove from the list of candidates all the items that were selected and return them. - pub fn new( + pub fn new_fits_in_memory( rtxn: &'t RoTxn, database: Database, index: u16, @@ -553,40 +579,6 @@ impl<'t, D: Distance> ImmutableTrees<'t, D> { Ok(ImmutableTrees { trees, _marker: marker::PhantomData }) } - /// Creates the structure by fetching all the children of the `start`ing tree nodes specified. - /// Keeps a reference to the transaction to ensure the pointers stays valid. - pub fn sub_tree_from_id( - rtxn: &'t RoTxn, - database: Database, - index: u16, - start: ItemId, - ) -> Result { - let mut trees = IntMap::default(); - let mut explore = vec![start]; - while let Some(current) = explore.pop() { - let bytes = - database.remap_data_type::().get(rtxn, &Key::tree(index, current))?.unwrap(); - let node: Node<'_, D> = NodeCodec::bytes_decode(bytes).unwrap(); - match node { - Node::Leaf(_leaf) => unreachable!(), - Node::Descendants(_descendants) => { - trees.insert(current, (bytes.len(), bytes.as_ptr())); - } - Node::SplitPlaneNormal(SplitPlaneNormal { left, right, normal: _ }) => { - trees.insert(current, (bytes.len(), bytes.as_ptr())); - explore.push(left); - explore.push(right); - } - } - } - - Ok(Self { trees, _marker: marker::PhantomData }) - } - - pub fn empty() -> Self { - Self { trees: IntMap::default(), _marker: marker::PhantomData } - } - /// Returns the tree node identified by the given ID. pub fn get(&self, item_id: ItemId) -> heed::Result>> { let (ptr, len) = match self.trees.get(&item_id) { diff --git a/src/tests/reader.rs b/src/tests/reader.rs index 7e23634..179cd3a 100644 --- a/src/tests/reader.rs +++ b/src/tests/reader.rs @@ -117,7 +117,10 @@ fn two_dimension_on_a_line() { // if we can't look into enough nodes we find some random points let ret = reader.nns(5).search_k(NonZeroUsize::new(1).unwrap()).by_item(&rtxn, 1).unwrap(); - insta::assert_snapshot!(NnsRes(ret), @"id(63): distance(62)"); + insta::assert_snapshot!(NnsRes(ret), @r" + id(24): distance(23) + id(60): distance(59) + "); // if we can look into all the node there is no inifinite loop and it works let ret = diff --git a/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points-2.snap b/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points-2.snap index 88b416d..35082e1 100644 --- a/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points-2.snap +++ b/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points-2.snap @@ -6,203 +6,209 @@ expression: handle Dumping index 0 Root: Metadata { dimensions: 30, items: RoaringBitmap<100 values between 0 and 99>, roots: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } -Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 16, right: 17, normal: [0.1738, 0.2578, -0.0461, 0.0510, -0.0521, -0.0580, 0.0696, 0.1589, 0.1435, 0.3797, "other ..."] }) -Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 27, right: 32, normal: [0.0555, 0.0806, 0.0143, -0.1385, 0.2849, 0.2319, -0.0446, -0.0610, -0.2684, -0.0590, "other ..."] }) -Tree 2: SplitPlaneNormal(SplitPlaneNormal { left: 40, right: 41, normal: [0.2392, -0.0605, 0.1095, 0.1468, 0.0647, -0.0015, -0.1760, -0.2809, -0.4246, -0.3074, "other ..."] }) -Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 45, right: 50, normal: [-0.2405, -0.3118, -0.0317, -0.0871, -0.0980, 0.1809, 0.2828, -0.0609, 0.0089, -0.1538, "other ..."] }) -Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 54, right: 63, normal: [0.0808, 0.1852, -0.0181, 0.2474, 0.1098, 0.0149, -0.3929, -0.0177, 0.1391, 0.0947, "other ..."] }) -Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 71, right: 72, normal: [-0.1497, -0.1444, -0.0162, 0.0031, -0.3458, 0.2424, 0.0059, -0.0709, 0.1749, -0.2611, "other ..."] }) -Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 80, right: 87, normal: [0.0190, 0.2016, 0.2233, 0.2480, 0.0147, 0.1042, -0.3418, 0.0209, -0.1837, -0.1727, "other ..."] }) -Tree 7: SplitPlaneNormal(SplitPlaneNormal { left: 93, right: 98, normal: [-0.0858, -0.2186, -0.1017, -0.3086, -0.1670, -0.2561, 0.1200, 0.0407, 0.1944, -0.1870, "other ..."] }) -Tree 8: SplitPlaneNormal(SplitPlaneNormal { left: 104, right: 107, normal: [0.1194, 0.1630, 0.2430, 0.2832, 0.0661, 0.0081, -0.4175, -0.1421, -0.1820, -0.2701, "other ..."] }) -Tree 9: SplitPlaneNormal(SplitPlaneNormal { left: 117, right: 118, normal: [0.1480, 0.1261, -0.0665, 0.3737, -0.0057, -0.1971, -0.5071, -0.2435, 0.0663, -0.0095, "other ..."] }) -Tree 10: Descendants(Descendants { descendants: [1, 2, 7, 8, 9, 10, 11, 28, 29, 31, 33, 34, 45, 50, 65, 74, 89, 97, 98] }) -Tree 15: SplitPlaneNormal(SplitPlaneNormal { left: 18, right: 51, normal: [-0.2138, 0.0571, -0.0776, 0.1494, 0.0759, -0.2498, 0.2368, 0.0106, -0.0278, 0.1747, "other ..."] }) -Tree 16: SplitPlaneNormal(SplitPlaneNormal { left: 10, right: 15, normal: [-0.0966, 0.0088, 0.1040, -0.2679, 0.0977, 0.0695, 0.1385, 0.0548, 0.3124, -0.1633, "other ..."] }) -Tree 17: Descendants(Descendants { descendants: [0, 3, 15, 16, 18, 21, 23, 24, 30, 37, 43, 44, 46, 47, 49, 53, 55, 62, 63, 66, 71, 73, 77, 78, 79, 80, 94, 95, 99] }) -Tree 18: Descendants(Descendants { descendants: [14, 19, 27, 32, 39, 40, 41, 48, 54, 58, 59, 68, 70, 72, 76, 84, 85, 88, 91, 93] }) -Tree 27: SplitPlaneNormal(SplitPlaneNormal { left: 73, right: 108, normal: [-0.2787, -0.1965, 0.0814, -0.2043, 0.0431, 0.2778, 0.1541, -0.0291, 0.2142, 0.2871, "other ..."] }) -Tree 32: SplitPlaneNormal(SplitPlaneNormal { left: 120, right: 121, normal: [0.0150, -0.3215, -0.1482, 0.0235, 0.1387, -0.1799, -0.1694, -0.0351, 0.1688, -0.3156, "other ..."] }) -Tree 33: Descendants(Descendants { descendants: [4, 5, 12, 17, 22, 35, 38, 42, 52, 57, 60, 61, 64, 67, 69, 75, 81, 82, 90, 92, 96] }) -Tree 34: Descendants(Descendants { descendants: [17, 20, 21, 22, 23, 37, 42, 46, 47, 53, 54, 55, 62, 67, 71, 73, 77, 81, 82, 90, 92, 93, 99] }) -Tree 37: SplitPlaneNormal(SplitPlaneNormal { left: 123, right: 124, normal: [-0.1304, 0.1195, 0.0237, -0.1315, 0.0979, -0.1541, -0.3484, 0.0547, 0.2803, -0.3469, "other ..."] }) -Tree 38: Descendants(Descendants { descendants: [6, 7, 9, 10, 11, 15, 24, 26, 28, 29, 30, 31, 33, 35, 38, 49, 50, 58, 60, 63, 69, 75, 80, 83] }) -Tree 39: SplitPlaneNormal(SplitPlaneNormal { left: 37, right: 38, normal: [0.1761, -0.3237, -0.0771, 0.0829, 0.1048, -0.1838, -0.0306, 0.2495, -0.1249, -0.0092, "other ..."] }) -Tree 40: SplitPlaneNormal(SplitPlaneNormal { left: 34, right: 39, normal: [-0.2772, -0.1070, -0.0457, 0.1794, 0.1804, 0.1983, 0.0126, -0.2826, -0.2110, 0.1753, "other ..."] }) -Tree 41: Descendants(Descendants { descendants: [16, 34, 43, 45, 51, 59, 64, 72, 89, 98] }) -Tree 42: Descendants(Descendants { descendants: [6, 13, 20, 25, 26, 36, 51, 56, 83, 86, 87] }) -Tree 45: SplitPlaneNormal(SplitPlaneNormal { left: 128, right: 129, normal: [-0.3684, 0.0008, -0.0807, 0.0681, -0.1419, -0.0001, -0.0154, 0.1576, 0.0101, 0.0771, "other ..."] }) -Tree 50: SplitPlaneNormal(SplitPlaneNormal { left: 133, right: 134, normal: [-0.3364, 0.0589, -0.0020, -0.0772, -0.1871, -0.0358, -0.0563, -0.1466, -0.1627, 0.1920, "other ..."] }) -Tree 51: SplitPlaneNormal(SplitPlaneNormal { left: 33, right: 42, normal: [0.0068, 0.0769, -0.2111, -0.1734, -0.0700, -0.0432, -0.2098, -0.1988, -0.1991, -0.1307, "other ..."] }) -Tree 54: SplitPlaneNormal(SplitPlaneNormal { left: 138, right: 139, normal: [-0.1643, 0.1602, -0.2199, -0.2451, -0.1178, 0.2557, 0.1298, 0.0327, 0.0103, -0.0055, "other ..."] }) -Tree 63: SplitPlaneNormal(SplitPlaneNormal { left: 141, right: 142, normal: [0.0065, -0.0485, -0.0992, -0.0442, 0.2479, 0.0409, 0.0901, -0.3365, -0.1733, 0.1287, "other ..."] }) -Tree 67: SplitPlaneNormal(SplitPlaneNormal { left: 144, right: 145, normal: [0.1903, -0.0961, 0.1925, -0.2574, -0.2317, 0.0783, 0.1623, 0.2120, -0.0413, 0.1303, "other ..."] }) -Tree 70: SplitPlaneNormal(SplitPlaneNormal { left: 147, right: 148, normal: [0.1108, -0.0947, 0.3407, 0.1735, -0.1439, -0.2324, -0.0712, -0.2749, -0.2086, -0.0004, "other ..."] }) -Tree 71: SplitPlaneNormal(SplitPlaneNormal { left: 67, right: 70, normal: [0.0999, 0.1850, -0.1401, -0.1190, -0.1531, -0.1959, 0.0606, 0.0370, 0.3700, 0.1146, "other ..."] }) -Tree 72: Descendants(Descendants { descendants: [1, 5, 9, 11, 19, 25, 28, 30, 35, 49, 50, 58, 66, 69, 75, 81, 88, 91, 99] }) -Tree 73: Descendants(Descendants { descendants: [1, 2, 6, 10, 21, 24, 26, 56, 82, 93] }) -Tree 80: SplitPlaneNormal(SplitPlaneNormal { left: 150, right: 151, normal: [0.2229, -0.3866, 0.2402, 0.0061, 0.1428, -0.0852, 0.2127, -0.0842, -0.0014, -0.2246, "other ..."] }) -Tree 87: SplitPlaneNormal(SplitPlaneNormal { left: 155, right: 156, normal: [-0.1265, -0.0081, -0.0437, -0.3091, -0.2324, 0.3360, 0.1516, 0.0989, -0.0661, 0.2188, "other ..."] }) -Tree 88: Descendants(Descendants { descendants: [0, 3, 8, 12, 14, 15, 30, 32, 36, 37, 43, 50, 54, 55, 57, 62, 66, 69, 76, 77, 79, 84, 86, 92, 94, 95, 99] }) -Tree 91: SplitPlaneNormal(SplitPlaneNormal { left: 160, right: 161, normal: [0.0901, -0.1422, 0.0808, 0.4557, -0.1263, -0.1972, 0.0589, -0.1268, -0.1789, -0.0074, "other ..."] }) -Tree 92: Descendants(Descendants { descendants: [13, 21, 43, 59, 83, 93] }) -Tree 93: SplitPlaneNormal(SplitPlaneNormal { left: 91, right: 92, normal: [0.0186, -0.1006, -0.0831, -0.0214, -0.1000, 0.1422, -0.0251, -0.0633, -0.1181, -0.4053, "other ..."] }) -Tree 98: SplitPlaneNormal(SplitPlaneNormal { left: 163, right: 164, normal: [-0.0601, 0.0890, 0.1118, 0.2139, 0.2523, -0.0009, -0.1579, -0.1218, 0.0301, -0.0263, "other ..."] }) -Tree 99: Descendants(Descendants { descendants: [11, 16, 17, 25, 28, 33, 34, 38, 46, 49, 52, 53, 60, 61, 63, 71, 75, 80, 81, 91] }) -Tree 104: SplitPlaneNormal(SplitPlaneNormal { left: 166, right: 171, normal: [0.1219, 0.3254, -0.0556, -0.1350, -0.1739, 0.2366, -0.0643, 0.2329, 0.0237, 0.3354, "other ..."] }) -Tree 107: SplitPlaneNormal(SplitPlaneNormal { left: 173, right: 174, normal: [0.1504, -0.3915, 0.0231, -0.0543, 0.1723, -0.1227, -0.0455, 0.3143, -0.0455, -0.2603, "other ..."] }) -Tree 108: SplitPlaneNormal(SplitPlaneNormal { left: 88, right: 99, normal: [-0.0075, -0.0900, 0.1567, -0.0452, 0.0956, -0.1871, -0.0356, -0.3843, 0.0220, -0.1451, "other ..."] }) -Tree 109: Descendants(Descendants { descendants: [2, 7, 11, 24, 27, 54, 66, 97, 99] }) -Tree 112: SplitPlaneNormal(SplitPlaneNormal { left: 176, right: 177, normal: [-0.2427, -0.2440, -0.0512, 0.0332, -0.0339, 0.4400, -0.0136, -0.0048, -0.0496, -0.1119, "other ..."] }) -Tree 115: SplitPlaneNormal(SplitPlaneNormal { left: 181, right: 182, normal: [0.1186, -0.2680, -0.0303, 0.1575, -0.0871, -0.3020, -0.3436, 0.1199, -0.1731, -0.1377, "other ..."] }) -Tree 116: SplitPlaneNormal(SplitPlaneNormal { left: 112, right: 115, normal: [0.1072, 0.2300, -0.0531, -0.0113, 0.0042, -0.0105, -0.0042, 0.1061, -0.1198, -0.1595, "other ..."] }) -Tree 117: SplitPlaneNormal(SplitPlaneNormal { left: 109, right: 116, normal: [0.0798, 0.0307, 0.0889, -0.0105, -0.1144, 0.2471, -0.0233, 0.0400, 0.1735, 0.0095, "other ..."] }) -Tree 118: Descendants(Descendants { descendants: [1, 4, 13, 34, 36, 45, 50, 56, 74, 89, 91, 98] }) -Tree 120: Descendants(Descendants { descendants: [7, 9, 18, 27, 40, 42, 44, 47, 64, 67, 68, 73, 78, 87, 96] }) -Tree 121: Descendants(Descendants { descendants: [4, 5, 13, 19, 20, 22, 23, 29, 31, 35, 39, 41, 45, 48, 51, 58, 59, 65, 70, 72, 74, 83, 85, 88, 89, 90, 97, 98] }) -Tree 123: Descendants(Descendants { descendants: [0, 8, 12, 14, 18, 27, 40, 44, 57, 65, 68, 74, 79, 84, 85, 86, 87, 94, 95, 96] }) -Tree 124: Descendants(Descendants { descendants: [1, 2, 3, 4, 5, 13, 19, 25, 32, 36, 39, 41, 48, 52, 56, 61, 66, 70, 76, 78, 88, 91, 97] }) -Tree 126: Descendants(Descendants { descendants: [8, 10, 13, 20, 21, 23, 27, 37, 43, 44, 45, 52, 56, 63, 64, 66, 67, 71, 73, 77, 79, 80, 82, 95, 96, 99] }) -Tree 127: Descendants(Descendants { descendants: [16, 24, 50, 72, 81, 89, 98] }) -Tree 128: SplitPlaneNormal(SplitPlaneNormal { left: 126, right: 127, normal: [-0.0325, -0.1206, 0.2451, 0.3714, -0.0099, -0.1293, -0.1042, -0.1818, -0.3650, -0.1787, "other ..."] }) -Tree 129: Descendants(Descendants { descendants: [1, 2, 3, 29, 36, 47, 54, 70, 74, 91, 97] }) -Tree 131: Descendants(Descendants { descendants: [0, 7, 9, 12, 14, 30, 32, 39, 42, 53, 55, 57, 58, 59, 76, 84, 88, 90, 94] }) -Tree 132: Descendants(Descendants { descendants: [4, 11, 19, 22, 31, 41, 48, 62, 65, 68, 69, 75, 78, 92] }) -Tree 133: SplitPlaneNormal(SplitPlaneNormal { left: 131, right: 132, normal: [0.1949, 0.0356, 0.0405, 0.1096, 0.3402, 0.1004, 0.1464, -0.1459, 0.1447, -0.2138, "other ..."] }) -Tree 134: Descendants(Descendants { descendants: [5, 6, 15, 17, 18, 25, 26, 28, 33, 34, 35, 38, 40, 46, 49, 51, 60, 61, 83, 85, 86, 87, 93] }) -Tree 136: Descendants(Descendants { descendants: [5, 15, 17, 35, 46, 49, 53, 55, 69, 71, 75, 78, 88] }) -Tree 137: Descendants(Descendants { descendants: [10, 22, 23, 30, 31, 33, 34, 38, 41, 42, 43, 48, 58, 59, 60, 64, 68, 72, 94, 99] }) -Tree 138: SplitPlaneNormal(SplitPlaneNormal { left: 136, right: 137, normal: [0.3939, -0.1742, 0.1461, 0.1937, 0.3098, 0.1434, 0.0170, -0.1041, -0.3780, -0.2889, "other ..."] }) -Tree 139: Descendants(Descendants { descendants: [0, 6, 12, 18, 20, 25, 44, 47, 51, 57, 61, 67, 73, 83, 86, 87, 90] }) -Tree 141: Descendants(Descendants { descendants: [3, 8, 14, 16, 21, 26, 29, 32, 36, 37, 39, 50, 54, 56, 62, 66, 76, 77, 79, 80, 81, 84, 85, 89, 92, 93, 95] }) -Tree 142: Descendants(Descendants { descendants: [1, 2, 4, 7, 9, 11, 13, 19, 24, 27, 28, 40, 45, 52, 63, 65, 70, 74, 82, 91, 96, 97, 98] }) -Tree 144: Descendants(Descendants { descendants: [2, 4, 8, 12, 13, 34, 36, 63, 64, 67, 84, 89, 92, 96] }) -Tree 145: Descendants(Descendants { descendants: [7, 20, 26, 27, 29, 31, 33, 39, 40, 45, 51, 57, 65, 68, 70, 74, 85, 90, 93, 97, 98] }) -Tree 147: Descendants(Descendants { descendants: [0, 3, 6, 14, 18, 21, 22, 32, 37, 41, 43, 44, 47, 48, 52, 56, 61, 62, 73, 76, 77, 78, 79, 82, 83, 86, 87, 95] }) -Tree 148: Descendants(Descendants { descendants: [10, 15, 16, 17, 23, 24, 38, 42, 46, 53, 54, 55, 59, 60, 71, 72, 80, 94] }) -Tree 150: Descendants(Descendants { descendants: [0, 6, 14, 15, 18, 32, 44, 46, 47, 57, 61, 62, 73, 76, 77, 78, 83, 84, 85, 86, 87] }) -Tree 151: Descendants(Descendants { descendants: [10, 12, 17, 22, 23, 30, 35, 37, 38, 41, 43, 48, 49, 51, 52, 53, 55, 59, 60, 65, 68, 69, 71, 72, 75, 79, 88, 92, 94, 99] }) -Tree 153: Descendants(Descendants { descendants: [16, 24, 34, 81] }) -Tree 154: Descendants(Descendants { descendants: [3, 4, 7, 9, 11, 13, 19, 21, 26, 28, 31, 36, 39, 42, 45, 50, 56, 58, 63, 64, 74, 80, 89, 90, 95, 96, 98] }) -Tree 155: SplitPlaneNormal(SplitPlaneNormal { left: 153, right: 154, normal: [0.0176, -0.1579, -0.0865, -0.1853, 0.2316, 0.1341, -0.0738, 0.2526, 0.0750, -0.2138, "other ..."] }) -Tree 156: Descendants(Descendants { descendants: [1, 2, 5, 8, 20, 25, 27, 29, 33, 40, 54, 66, 67, 70, 82, 91, 93, 97] }) -Tree 158: Descendants(Descendants { descendants: [3, 9, 23, 29, 32, 36, 39, 45, 48, 56, 57, 58, 74, 76, 77, 95] }) -Tree 159: Descendants(Descendants { descendants: [5, 8, 15, 18, 20, 27, 44, 47, 61, 65, 67, 70, 78, 86, 87] }) -Tree 160: SplitPlaneNormal(SplitPlaneNormal { left: 158, right: 159, normal: [-0.0754, 0.0080, 0.0159, -0.0275, -0.2499, 0.2907, 0.3605, -0.1126, -0.1845, 0.2383, "other ..."] }) -Tree 161: Descendants(Descendants { descendants: [2, 7, 10, 16, 24, 30, 33, 34, 42, 50, 54, 60, 63, 64, 68, 72, 79, 80, 81, 89, 90, 94, 96, 97, 98, 99] }) -Tree 163: Descendants(Descendants { descendants: [0, 1, 6, 12, 22, 25, 26, 31, 35, 37, 40, 41, 46, 49, 51, 52, 53, 55, 69, 71, 73, 82, 85, 88] }) -Tree 164: Descendants(Descendants { descendants: [4, 11, 14, 17, 19, 28, 38, 62, 66, 75, 84, 91, 92] }) -Tree 166: Descendants(Descendants { descendants: [10, 22, 28, 31, 35, 38, 42, 43, 46, 49, 52, 59, 60, 75] }) -Tree 167: Descendants(Descendants { descendants: [23, 71, 87] }) -Tree 168: Descendants(Descendants { descendants: [5, 6, 15, 18, 47, 48, 57, 61, 65, 70, 76, 78, 83, 85, 86, 88, 90] }) -Tree 169: Descendants(Descendants { descendants: [0, 7, 9, 12, 14, 17, 24, 30, 37, 40, 44, 53, 54, 55, 62, 68, 69, 73, 79, 84, 95, 99] }) -Tree 170: SplitPlaneNormal(SplitPlaneNormal { left: 168, right: 169, normal: [0.3965, 0.0791, 0.2059, -0.0066, -0.0920, -0.1262, 0.2075, -0.0572, -0.0955, -0.0546, "other ..."] }) -Tree 171: SplitPlaneNormal(SplitPlaneNormal { left: 167, right: 170, normal: [0.1004, -0.2446, 0.0208, 0.1314, -0.1788, 0.1577, 0.2874, 0.2605, 0.1742, -0.0758, "other ..."] }) -Tree 173: Descendants(Descendants { descendants: [1, 2, 3, 8, 13, 16, 19, 20, 21, 25, 27, 33, 45, 63, 66, 67, 74, 80, 81, 82, 91, 96, 97] }) -Tree 174: Descendants(Descendants { descendants: [4, 11, 26, 29, 32, 34, 36, 39, 41, 50, 51, 56, 58, 64, 72, 77, 89, 92, 93, 94, 98] }) -Tree 176: Descendants(Descendants { descendants: [5, 9, 10, 15, 17, 23, 28, 35, 38, 42, 46, 53, 60, 63, 67, 69, 71, 75, 78, 80, 81, 83, 87] }) -Tree 177: Descendants(Descendants { descendants: [12, 14, 19, 25, 30, 33, 49, 58, 59, 62, 65, 76, 84, 86, 88] }) -Tree 179: Descendants(Descendants { descendants: [0, 3, 6, 8, 16, 18, 20, 21, 29, 32, 37, 39, 40, 43, 44, 47, 48, 52, 55, 57, 61, 64, 68, 70, 73, 77, 79, 85, 95, 96] }) -Tree 180: Descendants(Descendants { descendants: [22, 26, 31, 41, 51] }) -Tree 181: SplitPlaneNormal(SplitPlaneNormal { left: 179, right: 180, normal: [0.1642, -0.2747, 0.1580, -0.2108, 0.1010, -0.1329, -0.1718, 0.0274, -0.1044, -0.4669, "other ..."] }) -Tree 182: Descendants(Descendants { descendants: [72, 82, 90, 92, 93, 94] }) -Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4988, 0.5189, 0.0009, 0.2303, 0.1099, 0.9680, 0.9963, 0.8902, 0.9113, 0.9266, "other ..."] }) +Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 94, right: 95, normal: [-0.1046, -0.1048, -0.2896, 0.1156, 0.1824, 0.0581, 0.1255, -0.4503, -0.1752, -0.0560, "other ..."] }) +Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 86, right: 87, normal: [-0.2341, 0.1458, 0.0773, 0.1020, 0.0417, 0.2230, -0.1430, -0.2387, -0.3313, 0.1407, "other ..."] }) +Tree 2: SplitPlaneNormal(SplitPlaneNormal { left: 74, right: 77, normal: [0.1217, 0.0833, -0.0056, 0.1328, -0.0380, 0.0330, 0.0748, -0.2139, -0.0114, 0.2295, "other ..."] }) +Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 58, right: 67, normal: [0.2244, -0.0253, -0.2056, 0.0824, 0.2003, 0.0394, 0.0264, 0.0473, -0.1382, -0.0086, "other ..."] }) +Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 50, right: 57, normal: [-0.0984, -0.1910, 0.0089, -0.1606, -0.0976, 0.1223, 0.2206, 0.0719, -0.0332, -0.1140, "other ..."] }) +Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 46, right: 49, normal: [-0.0789, -0.0919, -0.2989, 0.0919, 0.1022, 0.0531, 0.1250, 0.1123, -0.2858, 0.1638, "other ..."] }) +Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 42, right: 43, normal: [0.0953, -0.3674, -0.1991, 0.1479, 0.1567, 0.2698, -0.0292, -0.4009, -0.2190, -0.2206, "other ..."] }) +Tree 7: SplitPlaneNormal(SplitPlaneNormal { left: 32, right: 35, normal: [0.0745, -0.0082, 0.0411, 0.0279, 0.1671, -0.0662, -0.1877, 0.0130, -0.1362, -0.1283, "other ..."] }) +Tree 8: SplitPlaneNormal(SplitPlaneNormal { left: 16, right: 27, normal: [-0.2393, 0.0454, 0.0895, -0.2982, -0.1505, 0.0530, 0.0785, 0.0330, 0.3852, 0.2541, "other ..."] }) +Tree 9: SplitPlaneNormal(SplitPlaneNormal { left: 14, right: 15, normal: [-0.3441, -0.2391, 0.1543, 0.1196, -0.1148, 0.1463, -0.0595, -0.2466, 0.0381, -0.0162, "other ..."] }) +Tree 10: SplitPlaneNormal(SplitPlaneNormal { left: 136, right: 137, normal: [0.1808, -0.0865, 0.0053, 0.0900, -0.1073, 0.1461, -0.0633, 0.0563, 0.0322, -0.1497, "other ..."] }) +Tree 13: SplitPlaneNormal(SplitPlaneNormal { left: 134, right: 135, normal: [0.0626, 0.0203, -0.0437, -0.2993, -0.1123, 0.1210, 0.2959, 0.3134, -0.1440, 0.1833, "other ..."] }) +Tree 14: SplitPlaneNormal(SplitPlaneNormal { left: 10, right: 13, normal: [-0.1772, -0.0157, -0.0850, 0.1352, 0.2172, 0.3184, -0.0247, -0.2431, -0.1115, -0.1358, "other ..."] }) +Tree 15: Descendants(Descendants { descendants: [1, 5, 16, 19, 25, 28, 30, 33, 42, 49, 56, 70, 74, 75, 81, 90, 99] }) +Tree 16: Descendants(Descendants { descendants: [1, 13, 21, 29, 45, 63, 66, 72, 89, 92, 93] }) +Tree 21: SplitPlaneNormal(SplitPlaneNormal { left: 126, right: 127, normal: [-0.3426, -0.0960, 0.3738, 0.0410, 0.0402, 0.0126, 0.1230, -0.2237, -0.1289, 0.2847, "other ..."] }) +Tree 26: SplitPlaneNormal(SplitPlaneNormal { left: 122, right: 123, normal: [-0.0978, 0.2141, -0.2216, -0.1517, -0.1213, -0.2904, 0.2197, 0.0148, 0.0256, -0.0488, "other ..."] }) +Tree 27: SplitPlaneNormal(SplitPlaneNormal { left: 21, right: 26, normal: [-0.2059, -0.2478, 0.0146, -0.1079, 0.1970, 0.2143, -0.0704, -0.1705, -0.1067, -0.2651, "other ..."] }) +Tree 30: SplitPlaneNormal(SplitPlaneNormal { left: 116, right: 117, normal: [-0.0259, 0.0465, 0.0335, 0.1701, 0.1725, -0.2288, -0.0436, -0.1488, 0.3655, -0.1590, "other ..."] }) +Tree 31: Descendants(Descendants { descendants: [5, 19, 25, 28, 31, 35, 41, 46, 49, 51, 59, 60, 90, 99] }) +Tree 32: SplitPlaneNormal(SplitPlaneNormal { left: 30, right: 31, normal: [-0.0995, -0.3281, 0.1549, 0.1141, -0.1495, 0.0941, -0.0629, -0.1079, 0.0170, -0.4129, "other ..."] }) +Tree 35: Descendants(Descendants { descendants: [1, 2, 8, 11, 13, 18, 20, 27, 29, 37, 39, 45, 50, 52, 63, 65, 67, 68, 73, 74, 84, 85, 88, 89, 91, 92, 93, 97] }) +Tree 38: SplitPlaneNormal(SplitPlaneNormal { left: 114, right: 115, normal: [-0.1620, -0.1045, 0.1269, -0.0604, 0.2697, -0.0311, 0.2440, -0.1090, -0.3467, -0.0549, "other ..."] }) +Tree 41: SplitPlaneNormal(SplitPlaneNormal { left: 110, right: 113, normal: [-0.2387, -0.0110, 0.0426, 0.0063, 0.0651, 0.1954, -0.0741, 0.1250, -0.0222, -0.1453, "other ..."] }) +Tree 42: SplitPlaneNormal(SplitPlaneNormal { left: 38, right: 41, normal: [0.1020, -0.2572, -0.0377, -0.1376, 0.0667, -0.0283, 0.0005, 0.1117, 0.0582, -0.2710, "other ..."] }) +Tree 43: Descendants(Descendants { descendants: [13, 20, 31, 33, 41, 49, 51, 58, 59, 60, 62, 63, 83] }) +Tree 46: SplitPlaneNormal(SplitPlaneNormal { left: 108, right: 109, normal: [-0.0368, -0.1399, -0.0107, 0.2844, -0.0220, 0.1301, -0.4263, -0.1719, 0.2193, -0.1886, "other ..."] }) +Tree 49: SplitPlaneNormal(SplitPlaneNormal { left: 104, right: 107, normal: [-0.2247, 0.0034, 0.0538, 0.2301, 0.3861, 0.0918, -0.2806, -0.2139, -0.1770, -0.0044, "other ..."] }) +Tree 50: Descendants(Descendants { descendants: [7, 9, 18, 19, 23, 24, 27, 45, 64, 81, 84, 95] }) +Tree 51: Descendants(Descendants { descendants: [13, 20, 34, 36, 51, 61, 67, 68, 73, 80, 83, 87] }) +Tree 54: SplitPlaneNormal(SplitPlaneNormal { left: 98, right: 99, normal: [0.1513, 0.0863, 0.2694, -0.2545, -0.1733, 0.3004, -0.1612, 0.1441, -0.1236, 0.0915, "other ..."] }) +Tree 55: Descendants(Descendants { descendants: [17, 21, 37, 41, 53, 54, 55, 56, 70, 71, 72, 79, 91] }) +Tree 56: SplitPlaneNormal(SplitPlaneNormal { left: 54, right: 55, normal: [-0.0376, 0.0783, -0.1737, -0.1964, -0.2991, -0.1252, 0.0759, -0.0757, 0.4579, -0.0415, "other ..."] }) +Tree 57: SplitPlaneNormal(SplitPlaneNormal { left: 51, right: 56, normal: [0.1959, -0.0521, 0.4353, 0.1663, -0.4041, -0.1843, -0.0176, 0.1009, -0.0109, 0.1246, "other ..."] }) +Tree 58: Descendants(Descendants { descendants: [5, 17, 22, 25, 42, 49, 71, 75, 81, 99] }) +Tree 59: Descendants(Descendants { descendants: [2, 27, 37, 73, 84, 91] }) +Tree 60: Descendants(Descendants { descendants: [1, 7, 9, 11, 16, 29, 65, 69, 83, 97] }) +Tree 65: SplitPlaneNormal(SplitPlaneNormal { left: 148, right: 149, normal: [-0.0690, -0.2810, 0.0648, 0.2297, -0.1815, 0.1520, 0.0921, 0.0986, -0.2982, 0.0677, "other ..."] }) +Tree 66: SplitPlaneNormal(SplitPlaneNormal { left: 60, right: 65, normal: [0.0746, 0.1798, 0.1707, 0.0568, -0.0043, -0.0352, -0.2617, -0.1400, 0.0376, -0.1896, "other ..."] }) +Tree 67: SplitPlaneNormal(SplitPlaneNormal { left: 59, right: 66, normal: [0.0678, -0.1792, 0.0873, -0.0232, 0.0879, -0.0526, 0.0465, 0.2410, 0.0000, -0.1470, "other ..."] }) +Tree 68: Descendants(Descendants { descendants: [1, 3, 5, 7, 9, 10, 11, 12, 16, 17, 25, 26, 27, 29, 33, 48, 55, 65, 69, 70, 72, 73, 74, 88, 96, 97] }) +Tree 73: SplitPlaneNormal(SplitPlaneNormal { left: 138, right: 139, normal: [0.1005, -0.0210, -0.3242, -0.0264, 0.1990, -0.1632, 0.1455, -0.1751, -0.0374, 0.0169, "other ..."] }) +Tree 74: SplitPlaneNormal(SplitPlaneNormal { left: 68, right: 73, normal: [0.0363, -0.0129, -0.1424, 0.1457, 0.1532, 0.0220, -0.0942, -0.2280, 0.1921, -0.3136, "other ..."] }) +Tree 77: Descendants(Descendants { descendants: [0, 2, 14, 15, 20, 21, 22, 23, 24, 40, 42, 43, 47, 49, 53, 58, 59, 62, 63, 71, 75, 76, 79, 81, 83, 87, 94, 98, 99] }) +Tree 78: Descendants(Descendants { descendants: [2, 19, 21, 22, 23, 24, 37, 44, 47, 48, 50, 61, 63, 64, 73, 77, 87, 94] }) +Tree 85: SplitPlaneNormal(SplitPlaneNormal { left: 128, right: 133, normal: [0.0668, 0.1174, 0.0746, -0.2448, -0.1969, -0.3184, 0.0904, -0.0832, -0.1610, 0.0381, "other ..."] }) +Tree 86: SplitPlaneNormal(SplitPlaneNormal { left: 78, right: 85, normal: [0.1310, -0.2508, 0.2970, -0.0137, -0.1836, -0.1572, 0.0576, 0.0822, -0.1664, -0.1609, "other ..."] }) +Tree 87: Descendants(Descendants { descendants: [1, 3, 10, 13, 18, 27, 29, 45, 65, 68, 84, 85, 88, 91, 93, 97] }) +Tree 92: SplitPlaneNormal(SplitPlaneNormal { left: 120, right: 121, normal: [-0.3227, -0.0834, 0.1801, 0.0311, -0.0272, 0.0564, 0.0296, -0.1368, 0.2542, 0.1934, "other ..."] }) +Tree 93: Descendants(Descendants { descendants: [2, 14, 15, 21, 23, 34, 37, 40, 41, 44, 47, 48, 53, 54, 59, 64, 71, 73, 76, 77, 79, 81, 86, 94, 95, 96, 98, 99] }) +Tree 94: SplitPlaneNormal(SplitPlaneNormal { left: 92, right: 93, normal: [0.4416, 0.0529, -0.2415, 0.0425, -0.0870, -0.2230, -0.0310, -0.0219, 0.1446, -0.1358, "other ..."] }) +Tree 95: Descendants(Descendants { descendants: [0, 13, 19, 24, 43, 45, 51, 58, 63, 75, 83, 87] }) +Tree 96: Descendants(Descendants { descendants: [0, 4, 6, 11, 14, 16, 25, 28, 32, 33, 35, 40, 42, 46, 47, 49, 57, 58, 66, 69, 75, 78, 86, 89, 90, 94, 99] }) +Tree 97: Descendants(Descendants { descendants: [22, 38, 43, 62, 63, 76, 98] }) +Tree 98: SplitPlaneNormal(SplitPlaneNormal { left: 96, right: 97, normal: [-0.0597, 0.0937, -0.1595, 0.0450, 0.3454, -0.2161, -0.1076, -0.0939, 0.1110, 0.0993, "other ..."] }) +Tree 99: Descendants(Descendants { descendants: [1, 2, 3, 5, 8, 10, 12, 15, 26, 29, 30, 31, 39, 44, 48, 50, 52, 59, 60, 65, 74, 77, 82, 85, 88, 92, 93, 96, 97] }) +Tree 100: Descendants(Descendants { descendants: [25, 35, 42, 90] }) +Tree 101: Descendants(Descendants { descendants: [0, 8, 11, 16, 28, 30, 31, 32, 39, 57, 60, 69, 74, 79, 86, 94, 95, 98] }) +Tree 102: Descendants(Descendants { descendants: [6, 12, 26, 37, 46, 50, 52, 66, 72, 80, 82, 84, 85, 93] }) +Tree 103: SplitPlaneNormal(SplitPlaneNormal { left: 101, right: 102, normal: [0.1812, 0.0738, -0.0592, -0.1117, -0.2662, 0.1438, -0.1302, -0.0805, 0.0475, -0.0151, "other ..."] }) +Tree 104: SplitPlaneNormal(SplitPlaneNormal { left: 100, right: 103, normal: [0.2188, 0.0901, -0.1051, 0.2012, -0.0195, 0.0044, 0.1303, -0.0036, 0.0430, 0.0761, "other ..."] }) +Tree 105: Descendants(Descendants { descendants: [4, 13, 20, 24, 33, 45, 47, 51, 54, 58, 61, 62, 63, 68, 76, 78, 83, 89] }) +Tree 106: Descendants(Descendants { descendants: [1, 3, 7, 9, 10, 18, 27, 29, 36, 38, 65, 88, 92, 97] }) +Tree 107: SplitPlaneNormal(SplitPlaneNormal { left: 105, right: 106, normal: [-0.1523, 0.2056, 0.0958, -0.2472, -0.0877, -0.0273, 0.0846, 0.2084, -0.0607, 0.1331, "other ..."] }) +Tree 108: Descendants(Descendants { descendants: [2, 5, 14, 15, 17, 19, 21, 22, 23, 34, 40, 43, 44, 48, 49, 53, 55, 56, 59, 64, 67, 70, 71, 73, 75, 77, 81, 87, 96, 99] }) +Tree 109: Descendants(Descendants { descendants: [41, 91] }) +Tree 110: Descendants(Descendants { descendants: [23, 40, 53, 71, 76, 96] }) +Tree 111: Descendants(Descendants { descendants: [5, 7, 8, 9, 15, 19, 22, 25, 34, 39, 44, 67, 68, 74, 81, 89, 90, 97] }) +Tree 112: Descendants(Descendants { descendants: [0, 4, 11, 14, 16, 17, 26, 28, 29, 32, 35, 36, 38, 42, 46, 55, 56, 61, 69, 72, 75, 78, 80, 86, 87, 94, 98, 99] }) +Tree 113: SplitPlaneNormal(SplitPlaneNormal { left: 111, right: 112, normal: [0.1293, 0.0155, -0.4001, 0.0365, 0.1227, -0.0296, 0.2242, 0.0992, 0.1322, -0.0542, "other ..."] }) +Tree 114: Descendants(Descendants { descendants: [1, 2, 3, 6, 12, 21, 24, 30, 37, 43, 47, 50, 52, 54, 57, 64, 66, 70, 73, 77, 79, 82, 84, 85, 91, 92, 93, 95] }) +Tree 115: Descendants(Descendants { descendants: [10, 18, 27, 45, 48, 65, 88] }) +Tree 116: Descendants(Descendants { descendants: [0, 4, 7, 9, 10, 12, 14, 15, 17, 26, 30, 33, 34, 36, 38, 42, 44, 48, 53, 55, 57, 58, 62, 69, 77, 82, 86, 87, 94, 96] }) +Tree 117: Descendants(Descendants { descendants: [3, 6, 16, 21, 22, 23, 24, 32, 40, 43, 47, 54, 56, 61, 64, 66, 70, 71, 72, 75, 76, 78, 79, 80, 81, 83, 95, 98] }) +Tree 118: Descendants(Descendants { descendants: [4, 6, 8, 16, 28, 29, 30, 50, 52, 57, 60, 66, 72, 80, 84, 85, 93] }) +Tree 119: Descendants(Descendants { descendants: [1, 3, 7, 9, 10, 11, 12, 18, 26, 27, 31, 38, 39, 62, 65, 69, 82, 88, 89, 91, 92, 97] }) +Tree 120: SplitPlaneNormal(SplitPlaneNormal { left: 118, right: 119, normal: [-0.0233, 0.0615, 0.1293, 0.0753, 0.1011, -0.0376, -0.1530, -0.1646, -0.0339, 0.0610, "other ..."] }) +Tree 121: Descendants(Descendants { descendants: [5, 17, 20, 22, 25, 32, 33, 35, 36, 42, 46, 49, 55, 56, 61, 67, 68, 70, 74, 78, 90] }) +Tree 122: Descendants(Descendants { descendants: [4, 6, 19, 20, 24, 26, 33, 34, 41, 59, 60, 62, 65, 67, 68, 74, 85, 88, 97] }) +Tree 123: Descendants(Descendants { descendants: [5, 8, 9, 12, 14, 25, 31, 35, 36, 38, 39, 46, 49, 51, 58, 61, 76, 80, 83, 90] }) +Tree 124: Descendants(Descendants { descendants: [0, 3, 11, 16, 27, 28, 30, 32, 40, 47, 50, 52, 53, 54, 56, 57, 64, 69, 70, 75, 77, 79, 81, 86, 91, 94, 95, 98, 99] }) +Tree 125: Descendants(Descendants { descendants: [2, 18, 23, 37, 43, 44, 55, 71, 73, 82, 84, 96] }) +Tree 126: SplitPlaneNormal(SplitPlaneNormal { left: 124, right: 125, normal: [0.3017, 0.1292, -0.1140, -0.4036, -0.1095, 0.0578, 0.0337, -0.0012, -0.1750, -0.0455, "other ..."] }) +Tree 127: Descendants(Descendants { descendants: [7, 10, 15, 17, 22, 42, 48, 78, 87] }) +Tree 128: Descendants(Descendants { descendants: [8, 11, 14, 16, 20, 28, 34, 39, 41, 52, 56, 57, 60, 62, 67, 74, 75, 79, 81, 83, 86, 92, 95] }) +Tree 129: Descendants(Descendants { descendants: [38, 58, 69] }) +Tree 130: Descendants(Descendants { descendants: [0, 4, 6, 12, 25, 26, 30, 31, 32, 33, 35, 36, 43, 46, 51, 53, 54, 55, 59, 66, 72, 76, 78, 80, 82, 89, 96, 98] }) +Tree 131: SplitPlaneNormal(SplitPlaneNormal { left: 129, right: 130, normal: [0.0693, -0.0115, 0.2573, 0.1690, -0.2336, 0.0726, -0.2050, 0.1030, 0.0271, 0.1887, "other ..."] }) +Tree 132: Descendants(Descendants { descendants: [5, 7, 9, 15, 17, 40, 42, 49, 70, 71, 90, 99] }) +Tree 133: SplitPlaneNormal(SplitPlaneNormal { left: 131, right: 132, normal: [-0.2847, 0.1853, 0.3249, -0.0359, -0.1252, -0.0141, 0.0226, -0.0352, -0.0125, 0.2438, "other ..."] }) +Tree 134: Descendants(Descendants { descendants: [13, 18, 20, 22, 24, 34, 35, 39, 45, 51, 61, 62, 63, 67, 82, 83, 87, 92] }) +Tree 135: Descendants(Descendants { descendants: [0, 3, 4, 8, 10, 11, 27, 29, 31, 38, 48, 50, 54, 57, 65, 68, 69, 73, 78, 84, 85, 88, 91, 94, 97] }) +Tree 136: Descendants(Descendants { descendants: [7, 9, 14, 15, 17, 23, 26, 36, 40, 44, 53, 55, 58, 59, 71, 76, 96, 98] }) +Tree 137: Descendants(Descendants { descendants: [2, 6, 12, 21, 32, 37, 41, 43, 46, 47, 52, 60, 64, 66, 72, 77, 79, 80, 86, 89, 93, 95] }) +Tree 138: Descendants(Descendants { descendants: [4, 6, 8, 30, 32, 36, 46, 50, 52, 56, 61, 64, 66, 67, 68, 78, 80, 89, 90, 93] }) +Tree 139: Descendants(Descendants { descendants: [13, 18, 19, 28, 31, 34, 35, 37, 38, 39, 41, 44, 45, 51, 54, 57, 60, 77, 82, 84, 85, 86, 91, 92, 95] }) +Tree 140: Descendants(Descendants { descendants: [3, 15, 18, 19, 23, 24, 31, 34, 39, 41, 44, 48, 77, 82, 87] }) +Tree 141: Descendants(Descendants { descendants: [14, 38, 40, 43, 53, 54, 55, 57, 61, 63, 76, 78, 79, 94, 96, 98] }) +Tree 142: Descendants(Descendants { descendants: [8, 12, 26, 30, 32, 47, 50, 52, 64, 67, 68, 80, 86, 88, 89, 95] }) +Tree 143: SplitPlaneNormal(SplitPlaneNormal { left: 141, right: 142, normal: [0.0244, 0.1309, 0.1279, -0.1674, -0.2818, 0.2524, -0.2403, 0.3085, 0.0604, 0.0122, "other ..."] }) +Tree 144: Descendants(Descendants { descendants: [21, 56, 66, 70, 72, 90, 93] }) +Tree 145: SplitPlaneNormal(SplitPlaneNormal { left: 143, right: 144, normal: [-0.1127, 0.0016, 0.3638, 0.2673, -0.1602, -0.1803, -0.1251, -0.1562, -0.0099, -0.3139, "other ..."] }) +Tree 146: SplitPlaneNormal(SplitPlaneNormal { left: 140, right: 145, normal: [-0.0607, 0.0343, -0.2090, -0.0664, 0.0306, -0.0318, 0.2317, 0.1321, 0.0706, -0.1569, "other ..."] }) +Tree 147: Descendants(Descendants { descendants: [0, 4, 6, 13, 20, 33, 35, 36, 45, 46, 51, 58, 59, 62] }) +Tree 148: SplitPlaneNormal(SplitPlaneNormal { left: 146, right: 147, normal: [-0.1888, -0.3656, -0.0991, 0.2517, 0.0054, 0.1412, 0.0332, -0.2868, -0.2962, -0.2298, "other ..."] }) +Tree 149: Descendants(Descendants { descendants: [10, 28, 60, 74, 85, 92] }) +Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5691, 0.2017, 0.2038, 0.2523, 0.1656, 0.7198, 0.9908, 0.9873, 0.1991, 0.2202, "other ..."] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4199, 0.2620, 0.2655, 0.8414, 0.0192, 0.3828, 0.2561, 0.2692, 0.0368, 0.4624, "other ..."] }) -Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0501, 0.7256, 0.0927, 0.8787, 0.0745, 0.4455, 0.1670, 0.5263, 0.3922, 0.6264, "other ..."] }) +Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9844, 0.4436, 0.6281, 0.0342, 0.3575, 0.3818, 0.0302, 0.0269, 0.2284, 0.6082, "other ..."] }) Item 3: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0001, 0.7870, 0.9674, 0.4568, 0.5250, 0.2701, 0.2417, 0.8742, 0.6869, 0.8759, "other ..."] }) -Item 4: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.7025, 0.3373, 0.4632, 0.7819, 0.8148, 0.1793, 0.1601, 0.3283, 0.8373, 0.0514, "other ..."] }) +Item 4: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6305, 0.1852, 0.0517, 0.5162, 0.4308, 0.9393, 0.3359, 0.8628, 0.0185, 0.6288, "other ..."] }) Item 5: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0850, 0.7778, 0.8818, 0.3427, 0.1293, 0.7240, 0.4773, 0.2871, 0.3988, 0.4014, "other ..."] }) -Item 6: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.3716, 0.3733, 0.0372, 0.6661, 0.0060, 0.0835, 0.1023, 0.9889, 0.4997, 0.3133, "other ..."] }) +Item 6: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.7732, 0.4859, 0.6940, 0.7124, 0.1809, 0.9183, 0.8297, 0.2409, 0.2959, 0.3889, "other ..."] }) Item 7: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5699, 0.5919, 0.7788, 0.3705, 0.3807, 0.1708, 0.3678, 0.5629, 0.0612, 0.4826, "other ..."] }) -Item 8: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9577, 0.1656, 0.3414, 0.9329, 0.4046, 0.9177, 0.2933, 0.5043, 0.1456, 0.5960, "other ..."] }) +Item 8: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.2606, 0.1377, 0.7441, 0.0135, 0.0619, 0.4194, 0.5945, 0.9413, 0.2151, 0.5847, "other ..."] }) Item 9: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8134, 0.9647, 0.6640, 0.4464, 0.7439, 0.6904, 0.3159, 0.7607, 0.3483, 0.9963, "other ..."] }) -Item 10: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9399, 0.1397, 0.3165, 0.9233, 0.4341, 0.1593, 0.9677, 0.5099, 0.2311, 0.6656, "other ..."] }) +Item 10: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0801, 0.9351, 0.7265, 0.8319, 0.4562, 0.3787, 0.7330, 0.9286, 0.1837, 0.8404, "other ..."] }) Item 11: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6560, 0.2343, 0.4079, 0.5972, 0.5766, 0.6739, 0.2985, 0.6167, 0.4834, 0.2818, "other ..."] }) -Item 12: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1980, 0.0291, 0.8259, 0.6539, 0.5040, 0.6432, 0.9540, 0.8003, 0.5856, 0.5106, "other ..."] }) +Item 12: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9924, 0.5685, 0.3723, 0.2297, 0.1589, 0.7127, 0.7569, 0.8008, 0.2684, 0.8629, "other ..."] }) Item 13: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1726, 0.7399, 0.0271, 0.8721, 0.8725, 0.4023, 0.1558, 0.1044, 0.2096, 0.2081, "other ..."] }) -Item 14: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8198, 0.7169, 0.1776, 0.3455, 0.4842, 0.9568, 0.4215, 0.1351, 0.8962, 0.4807, "other ..."] }) +Item 14: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5341, 0.5373, 0.3614, 0.1611, 0.7268, 0.7789, 0.5822, 0.5474, 0.7846, 0.3485, "other ..."] }) Item 15: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6031, 0.2970, 0.9485, 0.0272, 0.4336, 0.1339, 0.2209, 0.8350, 0.2566, 0.9481, "other ..."] }) -Item 16: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8233, 0.8458, 0.7622, 0.9391, 0.2141, 0.4733, 0.1540, 0.0635, 0.2034, 0.3980, "other ..."] }) +Item 16: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6272, 0.7204, 0.4137, 0.3103, 0.8987, 0.1995, 0.9046, 0.4746, 0.5808, 0.6296, "other ..."] }) Item 17: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0819, 0.5362, 0.8215, 0.2263, 0.3109, 0.2738, 0.6133, 0.5147, 0.9334, 0.9877, "other ..."] }) -Item 18: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0440, 0.7657, 0.2987, 0.6865, 0.6893, 0.7138, 0.5424, 0.8816, 0.8798, 0.8051, "other ..."] }) +Item 18: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4160, 0.5313, 0.4760, 0.2117, 0.7608, 0.2017, 0.5997, 0.4663, 0.2783, 0.8645, "other ..."] }) Item 19: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1390, 0.7531, 0.3249, 0.8754, 0.9984, 0.7362, 0.0281, 0.2016, 0.9443, 0.1989, "other ..."] }) -Item 20: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6197, 0.4551, 0.7833, 0.2397, 0.0793, 0.5853, 0.5778, 0.2563, 0.0007, 0.1909, "other ..."] }) +Item 20: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8596, 0.0010, 0.8143, 0.8791, 0.7726, 0.7088, 0.0896, 0.3240, 0.1309, 0.5004, "other ..."] }) Item 21: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6252, 0.9240, 0.7227, 0.6810, 0.2563, 0.3321, 0.2283, 0.9226, 0.8494, 0.0356, "other ..."] }) -Item 22: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5495, 0.1951, 0.6711, 0.1160, 0.8283, 0.7836, 0.9972, 0.8724, 0.5824, 0.0227, "other ..."] }) +Item 22: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1915, 0.2687, 0.7671, 0.6234, 0.9868, 0.7270, 0.5404, 0.6695, 0.9427, 0.5441, "other ..."] }) Item 23: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9915, 0.6886, 0.1976, 0.1725, 0.6776, 0.1356, 0.3842, 0.4424, 0.6939, 0.8016, "other ..."] }) -Item 24: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8996, 0.9406, 0.3020, 0.7528, 0.6198, 0.0976, 0.7705, 0.3189, 0.0909, 0.7571, "other ..."] }) +Item 24: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4766, 0.1355, 0.7071, 0.8291, 0.7740, 0.3245, 0.2792, 0.0711, 0.6141, 0.7858, "other ..."] }) Item 25: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0116, 0.5323, 0.3940, 0.1382, 0.1987, 0.7287, 0.4026, 0.1442, 0.5957, 0.0340, "other ..."] }) -Item 26: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6011, 0.2709, 0.5131, 0.2078, 0.4573, 0.5433, 0.0019, 0.9903, 0.2598, 0.2025, "other ..."] }) +Item 26: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9958, 0.2017, 0.2902, 0.3911, 0.0928, 0.5717, 0.3145, 0.7503, 0.4984, 0.9545, "other ..."] }) Item 27: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.3569, 0.9070, 0.8412, 0.3201, 0.6998, 0.8674, 0.5494, 0.2322, 0.2969, 0.9787, "other ..."] }) -Item 28: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1063, 0.1748, 0.2458, 0.7798, 0.3720, 0.4174, 0.1471, 0.0428, 0.5633, 0.6777, "other ..."] }) +Item 28: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1562, 0.4070, 0.0880, 0.9745, 0.7060, 0.0318, 0.7282, 0.6670, 0.8390, 0.2992, "other ..."] }) Item 29: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6021, 0.0690, 0.1080, 0.2535, 0.6817, 0.7899, 0.3297, 0.8656, 0.1566, 0.3560, "other ..."] }) -Item 30: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8072, 0.0892, 0.5923, 0.7761, 0.4024, 0.9081, 0.5860, 0.8422, 0.4884, 0.9159, "other ..."] }) +Item 30: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6452, 0.9110, 0.7132, 0.4191, 0.4112, 0.5348, 0.4404, 0.8581, 0.4330, 0.8951, "other ..."] }) Item 31: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.7584, 0.3448, 0.7315, 0.5405, 0.6797, 0.3253, 0.8611, 0.0846, 0.0174, 0.0882, "other ..."] }) -Item 32: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.3727, 0.6472, 0.0139, 0.0702, 0.3184, 0.1636, 0.0705, 0.9162, 0.4068, 0.2656, "other ..."] }) +Item 32: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6471, 0.6307, 0.8962, 0.2893, 0.4631, 0.1205, 0.7605, 0.8382, 0.9778, 0.0805, "other ..."] }) Item 33: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.3494, 0.5787, 0.8027, 0.9625, 0.5944, 0.6781, 0.4204, 0.5899, 0.0209, 0.9001, "other ..."] }) -Item 34: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.3212, 0.0368, 0.7054, 0.9818, 0.4610, 0.0820, 0.0244, 0.0167, 0.1143, 0.5339, "other ..."] }) +Item 34: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4709, 0.1850, 0.4666, 0.4263, 0.6792, 0.7046, 0.0851, 0.2056, 0.7178, 0.4810, "other ..."] }) Item 35: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.3281, 0.1178, 0.0533, 0.4172, 0.3990, 0.0395, 0.8533, 0.1435, 0.9799, 0.4063, "other ..."] }) -Item 36: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5610, 0.9772, 0.0580, 0.7507, 0.8983, 0.4885, 0.1873, 0.5225, 0.5751, 0.0231, "other ..."] }) +Item 36: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0761, 0.8969, 0.0492, 0.2230, 0.4939, 0.5646, 0.6062, 0.4992, 0.1078, 0.5006, "other ..."] }) Item 37: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6603, 0.3675, 0.1019, 0.2193, 0.3180, 0.0591, 0.9934, 0.8583, 0.7473, 0.3644, "other ..."] }) -Item 38: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5539, 0.1651, 0.6811, 0.5493, 0.9971, 0.0290, 0.3549, 0.0161, 0.3525, 0.1670, "other ..."] }) +Item 38: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1991, 0.5403, 0.0405, 0.1756, 0.8858, 0.4640, 0.9576, 0.3734, 0.2786, 0.0953, "other ..."] }) Item 39: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4498, 0.4107, 0.9992, 0.3928, 0.4779, 0.4661, 0.1282, 0.8140, 0.7490, 0.5641, "other ..."] }) -Item 40: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4446, 0.4059, 0.5113, 0.2566, 0.1384, 0.9068, 0.8248, 0.7463, 0.2566, 0.7379, "other ..."] }) +Item 40: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4070, 0.1137, 0.5368, 0.9245, 0.2500, 0.0250, 0.7935, 0.0007, 0.7585, 0.4630, "other ..."] }) Item 41: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.7821, 0.0623, 0.1168, 0.3609, 0.6040, 0.8336, 0.0911, 0.2181, 0.7485, 0.0281, "other ..."] }) -Item 42: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1071, 0.2066, 0.9711, 0.8793, 0.2194, 0.4553, 0.3941, 0.7292, 0.5579, 0.4599, "other ..."] }) +Item 42: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5091, 0.0906, 0.6799, 0.0227, 0.0664, 0.4943, 0.6480, 0.2907, 0.1529, 0.9099, "other ..."] }) Item 43: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8608, 0.8689, 0.4918, 0.2239, 0.9291, 0.0622, 0.6843, 0.4184, 0.4703, 0.3202, "other ..."] }) -Item 44: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8239, 0.7788, 0.5844, 0.5306, 0.1690, 0.9621, 0.5922, 0.4139, 0.2589, 0.8403, "other ..."] }) +Item 44: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8975, 0.9026, 0.3267, 0.2830, 0.9081, 0.1656, 0.4371, 0.8825, 0.9425, 0.4156, "other ..."] }) Item 45: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9838, 0.4742, 0.5307, 0.6989, 0.9323, 0.2140, 0.1371, 0.1113, 0.0322, 0.3001, "other ..."] }) -Item 46: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.3006, 0.8686, 0.8836, 0.4165, 0.2846, 0.1031, 0.4936, 0.6262, 0.2305, 0.7956, "other ..."] }) +Item 46: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.3753, 0.2408, 0.2653, 0.7672, 0.0966, 0.2104, 0.2312, 0.3469, 0.6364, 0.3652, "other ..."] }) Item 47: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4506, 0.8658, 0.1164, 0.2339, 0.2266, 0.9050, 0.5849, 0.9792, 0.5951, 0.7706, "other ..."] }) -Item 48: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.2364, 0.6117, 0.6229, 0.5530, 0.9892, 0.5707, 0.1225, 0.4371, 0.4740, 0.5488, "other ..."] }) +Item 48: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5486, 0.9838, 0.6668, 0.1541, 0.6342, 0.9678, 0.9183, 0.4694, 0.4923, 0.5748, "other ..."] }) Item 49: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1322, 0.0670, 0.3404, 0.5339, 0.0229, 0.5964, 0.5497, 0.3819, 0.6553, 0.7129, "other ..."] }) -Item 50: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.7296, 0.4068, 0.9712, 0.8462, 0.0997, 0.0066, 0.1904, 0.9582, 0.0554, 0.2650, "other ..."] }) +Item 50: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.7915, 0.8245, 0.0562, 0.0983, 0.1049, 0.9047, 0.3248, 0.8740, 0.7597, 0.5026, "other ..."] }) Item 51: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.3643, 0.3282, 0.2580, 0.4477, 0.5920, 0.3581, 0.3502, 0.2441, 0.1707, 0.1243, "other ..."] }) -Item 52: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8419, 0.7453, 0.3740, 0.0989, 0.8923, 0.2492, 0.9620, 0.1276, 0.8429, 0.6416, "other ..."] }) +Item 52: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4767, 0.5844, 0.9410, 0.8368, 0.3227, 0.7505, 0.1099, 0.8573, 0.7832, 0.9095, "other ..."] }) Item 53: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5928, 0.6267, 0.1717, 0.1604, 0.6506, 0.0302, 0.8289, 0.5930, 0.9304, 0.6067, "other ..."] }) -Item 54: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.7219, 0.7828, 0.4664, 0.9112, 0.0509, 0.9751, 0.7915, 0.5914, 0.1674, 0.5170, "other ..."] }) +Item 54: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5760, 0.3888, 0.2231, 0.5688, 0.4859, 0.2078, 0.1466, 0.3177, 0.9709, 0.6116, "other ..."] }) Item 55: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6095, 0.6335, 0.4740, 0.0746, 0.3871, 0.1016, 0.6414, 0.3076, 0.5484, 0.7602, "other ..."] }) -Item 56: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8092, 0.6173, 0.9649, 0.1808, 0.4181, 0.1213, 0.1962, 0.3540, 0.7013, 0.1030, "other ..."] }) +Item 56: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.2802, 0.2739, 0.7232, 0.8222, 0.4219, 0.5532, 0.3637, 0.2164, 0.9099, 0.0570, "other ..."] }) Item 57: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1524, 0.3441, 0.2368, 0.4350, 0.5328, 0.3005, 0.7021, 0.3614, 0.6369, 0.7984, "other ..."] }) -Item 58: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.2536, 0.2703, 0.9993, 0.5952, 0.8735, 0.9532, 0.1737, 0.8924, 0.8668, 0.0666, "other ..."] }) +Item 58: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0312, 0.3130, 0.1591, 0.7236, 0.5735, 0.2308, 0.5460, 0.3421, 0.0572, 0.6052, "other ..."] }) Item 59: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6227, 0.1202, 0.9715, 0.3936, 0.3423, 0.7479, 0.6526, 0.1867, 0.5568, 0.0922, "other ..."] }) -Item 60: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0026, 0.4216, 0.7622, 0.5439, 0.8554, 0.1796, 0.6987, 0.4025, 0.4228, 0.6281, "other ..."] }) +Item 60: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5270, 0.0955, 0.5762, 0.0805, 0.3199, 0.9090, 0.6208, 0.8156, 0.2419, 0.3181, "other ..."] }) Item 61: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1347, 0.7000, 0.0530, 0.4959, 0.8227, 0.9831, 0.5433, 0.5201, 0.7924, 0.3847, "other ..."] }) -Item 62: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5808, 0.7813, 0.2647, 0.6765, 0.3207, 0.2739, 0.9840, 0.8998, 0.8740, 0.1552, "other ..."] }) +Item 62: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.2508, 0.5844, 0.0041, 0.8819, 0.9161, 0.9307, 0.1548, 0.3934, 0.6088, 0.6955, "other ..."] }) Item 63: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9221, 0.3578, 0.3207, 0.9945, 0.9288, 0.4608, 0.3001, 0.0296, 0.4678, 0.7422, "other ..."] }) -Item 64: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9904, 0.6222, 0.6460, 0.6455, 0.9772, 0.9037, 0.7883, 0.2515, 0.1391, 0.0313, "other ..."] }) +Item 64: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5425, 0.6924, 0.4998, 0.1669, 0.2662, 0.0321, 0.0579, 0.4807, 0.8837, 0.6801, "other ..."] }) Item 65: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5677, 0.1247, 0.4928, 0.4097, 0.8433, 0.9238, 0.7848, 0.4437, 0.4696, 0.9886, "other ..."] }) -Item 66: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0790, 0.9025, 0.2829, 0.9626, 0.1784, 0.4087, 0.1928, 0.9560, 0.0659, 0.3717, "other ..."] }) +Item 66: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.7230, 0.6671, 0.4246, 0.9173, 0.8003, 0.2369, 0.6229, 0.1692, 0.5419, 0.5009, "other ..."] }) Item 67: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5299, 0.5421, 0.8194, 0.1018, 0.5426, 0.9350, 0.3228, 0.7979, 0.7473, 0.1118, "other ..."] }) -Item 68: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9612, 0.0730, 0.9112, 0.5646, 0.4922, 0.6449, 0.8764, 0.1564, 0.2957, 0.6417, "other ..."] }) +Item 68: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1253, 0.7856, 0.7688, 0.6142, 0.4916, 0.9840, 0.6736, 0.3734, 0.8886, 0.9260, "other ..."] }) Item 69: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6163, 0.7762, 0.4365, 0.6713, 0.5647, 0.3449, 0.6615, 0.9430, 0.5941, 0.3563, "other ..."] }) -Item 70: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9215, 0.0521, 0.5452, 0.0279, 0.2587, 0.6949, 0.7256, 0.8297, 0.7666, 0.9061, "other ..."] }) +Item 70: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4624, 0.6183, 0.8460, 0.0977, 0.1144, 0.8153, 0.3813, 0.3064, 0.7226, 0.7813, "other ..."] }) Item 71: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6478, 0.9371, 0.2378, 0.4279, 0.1400, 0.2146, 0.3193, 0.7330, 0.7932, 0.7295, "other ..."] }) -Item 72: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9326, 0.0457, 0.5946, 0.7477, 0.6199, 0.1108, 0.4471, 0.9398, 0.0752, 0.2719, "other ..."] }) +Item 72: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.7431, 0.2036, 0.5143, 0.0838, 0.1408, 0.2708, 0.6502, 0.7476, 0.0027, 0.2546, "other ..."] }) Item 73: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4640, 0.7218, 0.0154, 0.0829, 0.4829, 0.5139, 0.4344, 0.5872, 0.2770, 0.3745, "other ..."] }) -Item 74: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9403, 0.8757, 0.3515, 0.4578, 0.4501, 0.3561, 0.3967, 0.1306, 0.5999, 0.3500, "other ..."] }) +Item 74: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5892, 0.1158, 0.9738, 0.8020, 0.1475, 0.8025, 0.6771, 0.6167, 0.3474, 0.9959, "other ..."] }) Item 75: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.3639, 0.3210, 0.3718, 0.7818, 0.6264, 0.2524, 0.6018, 0.4059, 0.9744, 0.3568, "other ..."] }) -Item 76: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1462, 0.7091, 0.0995, 0.5263, 0.6013, 0.7575, 0.0023, 0.4143, 0.7932, 0.8820, "other ..."] }) +Item 76: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8721, 0.2087, 0.1389, 0.3781, 0.8195, 0.4335, 0.9500, 0.3030, 0.6022, 0.9074, "other ..."] }) Item 77: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6003, 0.7202, 0.3803, 0.5052, 0.4006, 0.6708, 0.0438, 0.8432, 0.8772, 0.6849, "other ..."] }) -Item 78: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.3603, 0.8546, 0.3370, 0.6774, 0.9610, 0.5030, 0.5232, 0.5720, 0.9014, 0.9452, "other ..."] }) +Item 78: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1648, 0.5622, 0.8622, 0.4060, 0.9234, 0.4541, 0.7880, 0.6254, 0.6776, 0.7990, "other ..."] }) Item 79: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8093, 0.7442, 0.3738, 0.9164, 0.5923, 0.7353, 0.5379, 0.6815, 0.5925, 0.7954, "other ..."] }) -Item 80: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9069, 0.8039, 0.9567, 0.7394, 0.1511, 0.2094, 0.0644, 0.3092, 0.4993, 0.7042, "other ..."] }) +Item 80: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.7110, 0.8746, 0.2891, 0.0877, 0.9762, 0.7313, 0.1369, 0.9363, 0.7791, 0.3066, "other ..."] }) Item 81: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.2370, 0.7334, 0.4755, 0.8921, 0.1448, 0.2971, 0.2116, 0.1124, 0.7297, 0.2965, "other ..."] }) -Item 82: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8627, 0.6146, 0.0070, 0.4325, 0.2349, 0.2019, 0.0674, 0.7314, 0.4522, 0.7026, "other ..."] }) +Item 82: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8911, 0.6624, 0.5524, 0.4579, 0.3863, 0.9061, 0.5681, 0.5999, 0.3466, 0.1909, "other ..."] }) Item 83: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.3071, 0.2166, 0.0566, 0.5153, 0.8628, 0.9601, 0.6390, 0.4052, 0.2759, 0.4989, "other ..."] }) -Item 84: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1394, 0.1883, 0.5325, 0.5892, 0.6697, 0.7687, 0.1885, 0.3976, 0.0690, 0.7557, "other ..."] }) +Item 84: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8972, 0.4273, 0.4040, 0.3423, 0.4314, 0.2713, 0.7759, 0.2579, 0.6453, 0.5287, "other ..."] }) Item 85: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4718, 0.3682, 0.4350, 0.3129, 0.1289, 0.7526, 0.8249, 0.5640, 0.9296, 0.8479, "other ..."] }) -Item 86: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0077, 0.4560, 0.1201, 0.5524, 0.2284, 0.4952, 0.7651, 0.4557, 0.0336, 0.8868, "other ..."] }) +Item 86: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8882, 0.2987, 0.1828, 0.1994, 0.2912, 0.6075, 0.9520, 0.7728, 0.8223, 0.4776, "other ..."] }) Item 87: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.2909, 0.8867, 0.3238, 0.4342, 0.3491, 0.4305, 0.8452, 0.0936, 0.1220, 0.3452, "other ..."] }) -Item 88: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1715, 0.3212, 0.3101, 0.2505, 0.1204, 0.6421, 0.3360, 0.8166, 0.4927, 0.2501, "other ..."] }) +Item 88: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8175, 0.6083, 0.8112, 0.0546, 0.9491, 0.9346, 0.7757, 0.8012, 0.1869, 0.8699, "other ..."] }) Item 89: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6270, 0.3774, 0.7874, 0.7272, 0.4240, 0.1508, 0.0360, 0.5710, 0.2254, 0.0950, "other ..."] }) -Item 90: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4935, 0.0936, 0.1667, 0.9665, 0.5290, 0.0019, 0.5783, 0.8122, 0.4687, 0.4643, "other ..."] }) +Item 90: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1152, 0.5199, 0.9058, 0.4778, 0.0567, 0.4204, 0.6870, 0.5782, 0.8064, 0.4503, "other ..."] }) Item 91: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8560, 0.9670, 0.3969, 0.5008, 0.1567, 0.7420, 0.0072, 0.1891, 0.9690, 0.0387, "other ..."] }) -Item 92: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.7904, 0.0072, 0.4569, 0.6627, 0.9265, 0.1001, 0.5258, 0.5369, 0.7636, 0.1074, "other ..."] }) +Item 92: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1678, 0.5258, 0.9396, 0.9581, 0.4475, 0.2638, 0.5845, 0.7472, 0.5972, 0.2040, "other ..."] }) Item 93: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.5034, 0.4728, 0.9950, 0.7630, 0.0154, 0.4453, 0.6893, 0.6996, 0.0246, 0.0245, "other ..."] }) -Item 94: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.7829, 0.4451, 0.3477, 0.8053, 0.8519, 0.3936, 0.3521, 0.1373, 0.3324, 0.7195, "other ..."] }) +Item 94: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.6528, 0.1518, 0.1914, 0.6531, 0.1864, 0.8516, 0.8513, 0.7597, 0.7184, 0.9471, "other ..."] }) Item 95: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8157, 0.8688, 0.2659, 0.6080, 0.5274, 0.1883, 0.7562, 0.8511, 0.6928, 0.8151, "other ..."] }) -Item 96: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1876, 0.9623, 0.5111, 0.9887, 0.7561, 0.7959, 0.8554, 0.0285, 0.1988, 0.8901, "other ..."] }) +Item 96: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8466, 0.5695, 0.6938, 0.2837, 0.1516, 0.5060, 0.6954, 0.6374, 0.2537, 0.2103, "other ..."] }) Item 97: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0850, 0.4087, 0.7257, 0.3157, 0.9526, 0.5290, 0.5818, 0.5460, 0.1906, 0.9422, "other ..."] }) -Item 98: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.9358, 0.4796, 0.9935, 0.8769, 0.5276, 0.4131, 0.0780, 0.0683, 0.1038, 0.6586, "other ..."] }) +Item 98: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.7869, 0.7930, 0.1927, 0.3278, 0.9169, 0.1851, 0.6830, 0.8456, 0.3333, 0.4058, "other ..."] }) Item 99: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8320, 0.5156, 0.6172, 0.6617, 0.4999, 0.2464, 0.4536, 0.3265, 0.2163, 0.5406, "other ..."] }) diff --git a/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points.snap b/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points.snap index e1eb123..fdcd285 100644 --- a/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points.snap +++ b/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points.snap @@ -6,116 +6,102 @@ expression: handle Dumping index 0 Root: Metadata { dimensions: 30, items: RoaringBitmap<100 values between 0 and 99>, roots: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } -Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 16, right: 17, normal: [0.1738, 0.2578, -0.0461, 0.0510, -0.0521, -0.0580, 0.0696, 0.1589, 0.1435, 0.3797, "other ..."] }) -Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 27, right: 32, normal: [0.0555, 0.0806, 0.0143, -0.1385, 0.2849, 0.2319, -0.0446, -0.0610, -0.2684, -0.0590, "other ..."] }) -Tree 2: SplitPlaneNormal(SplitPlaneNormal { left: 40, right: 41, normal: [0.2392, -0.0605, 0.1095, 0.1468, 0.0647, -0.0015, -0.1760, -0.2809, -0.4246, -0.3074, "other ..."] }) -Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 45, right: 50, normal: [-0.2405, -0.3118, -0.0317, -0.0871, -0.0980, 0.1809, 0.2828, -0.0609, 0.0089, -0.1538, "other ..."] }) -Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 54, right: 63, normal: [0.0808, 0.1852, -0.0181, 0.2474, 0.1098, 0.0149, -0.3929, -0.0177, 0.1391, 0.0947, "other ..."] }) -Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 71, right: 72, normal: [-0.1497, -0.1444, -0.0162, 0.0031, -0.3458, 0.2424, 0.0059, -0.0709, 0.1749, -0.2611, "other ..."] }) -Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 80, right: 87, normal: [0.0190, 0.2016, 0.2233, 0.2480, 0.0147, 0.1042, -0.3418, 0.0209, -0.1837, -0.1727, "other ..."] }) -Tree 7: SplitPlaneNormal(SplitPlaneNormal { left: 93, right: 98, normal: [-0.0858, -0.2186, -0.1017, -0.3086, -0.1670, -0.2561, 0.1200, 0.0407, 0.1944, -0.1870, "other ..."] }) -Tree 8: SplitPlaneNormal(SplitPlaneNormal { left: 104, right: 107, normal: [0.1194, 0.1630, 0.2430, 0.2832, 0.0661, 0.0081, -0.4175, -0.1421, -0.1820, -0.2701, "other ..."] }) -Tree 9: SplitPlaneNormal(SplitPlaneNormal { left: 117, right: 118, normal: [0.1480, 0.1261, -0.0665, 0.3737, -0.0057, -0.1971, -0.5071, -0.2435, 0.0663, -0.0095, "other ..."] }) -Tree 10: Descendants(Descendants { descendants: [1, 7, 9, 10, 11, 14, 26, 29, 31, 33, 36, 45, 48, 50, 62, 65, 70, 86, 89, 90, 96, 97] }) -Tree 11: Descendants(Descendants { descendants: [8, 13, 22, 30, 34, 41, 46, 51, 52, 56, 59, 60, 64, 78, 83, 87, 92, 93] }) -Tree 12: Descendants(Descendants { descendants: [2, 4, 5, 12, 17, 18, 19, 25, 27, 32, 35, 39, 40, 42, 44, 57, 61, 66, 67, 69, 72, 74, 75, 76, 80, 81, 84, 85, 91, 98] }) -Tree 13: Descendants(Descendants { descendants: [0, 28] }) -Tree 14: SplitPlaneNormal(SplitPlaneNormal { left: 12, right: 13, normal: [0.2731, -0.0786, -0.1327, 0.3628, 0.2345, -0.2280, -0.2013, -0.0272, -0.0493, -0.2326, "other ..."] }) -Tree 15: SplitPlaneNormal(SplitPlaneNormal { left: 11, right: 14, normal: [-0.2567, 0.1567, 0.1493, -0.0293, 0.2374, -0.1484, -0.0445, 0.2906, 0.1958, 0.1779, "other ..."] }) -Tree 16: SplitPlaneNormal(SplitPlaneNormal { left: 10, right: 15, normal: [-0.0966, 0.0088, 0.1040, -0.2679, 0.0977, 0.0695, 0.1385, 0.0548, 0.3124, -0.1633, "other ..."] }) -Tree 17: Descendants(Descendants { descendants: [3, 6, 15, 16, 20, 21, 23, 24, 37, 38, 43, 47, 49, 53, 54, 55, 58, 63, 68, 71, 73, 77, 79, 82, 88, 94, 95, 99] }) -Tree 19: Descendants(Descendants { descendants: [3, 6, 21, 26, 28, 37, 62, 68, 77, 90, 91, 95, 96] }) -Tree 20: Descendants(Descendants { descendants: [10, 36, 48] }) -Tree 21: Descendants(Descendants { descendants: [20, 22, 43, 54, 55, 58, 63, 71, 76, 82, 93, 94] }) -Tree 22: Descendants(Descendants { descendants: [4, 15, 17, 18, 25, 32, 33, 38, 49, 53, 57, 60, 61, 69, 74, 75, 79, 84, 88] }) -Tree 23: SplitPlaneNormal(SplitPlaneNormal { left: 21, right: 22, normal: [-0.3791, -0.0730, -0.1764, 0.0305, 0.0613, 0.0636, 0.1593, 0.1123, 0.2905, -0.0217, "other ..."] }) -Tree 24: Descendants(Descendants { descendants: [0, 1, 8, 11, 14, 34, 40, 81, 86, 92, 99] }) -Tree 25: SplitPlaneNormal(SplitPlaneNormal { left: 23, right: 24, normal: [0.2076, -0.0553, -0.0089, 0.1387, -0.0785, -0.1300, -0.2254, 0.0608, -0.1784, -0.2486, "other ..."] }) -Tree 26: SplitPlaneNormal(SplitPlaneNormal { left: 20, right: 25, normal: [0.0553, 0.0790, 0.1994, -0.2354, 0.0693, -0.1209, 0.1183, 0.1277, 0.2898, 0.2283, "other ..."] }) -Tree 27: SplitPlaneNormal(SplitPlaneNormal { left: 19, right: 26, normal: [0.0473, -0.3036, 0.0457, -0.1234, 0.1619, 0.1471, 0.2030, 0.0749, -0.0642, -0.1674, "other ..."] }) -Tree 28: Descendants(Descendants { descendants: [2, 23, 27, 29, 47, 65, 67, 73, 78, 85, 87] }) -Tree 29: Descendants(Descendants { descendants: [5, 7, 9, 12, 19, 31, 35, 39, 41, 42, 44, 50, 52, 59, 70, 72, 80, 83, 97, 98] }) -Tree 30: Descendants(Descendants { descendants: [13, 16, 24, 30, 45, 46, 51, 56, 64, 66, 89] }) -Tree 31: SplitPlaneNormal(SplitPlaneNormal { left: 29, right: 30, normal: [0.1071, 0.1977, -0.0913, 0.0567, 0.0582, 0.0759, -0.2098, -0.1768, -0.1752, -0.1923, "other ..."] }) -Tree 32: SplitPlaneNormal(SplitPlaneNormal { left: 28, right: 31, normal: [0.1214, -0.1399, 0.2165, 0.3373, 0.0917, -0.0955, -0.3803, -0.1108, 0.0250, -0.3141, "other ..."] }) -Tree 34: Descendants(Descendants { descendants: [4, 6, 8, 12, 17, 18, 21, 23, 28, 37, 47, 52, 53, 55, 67, 71, 73, 74, 77, 78, 81, 82, 86, 93, 96, 99] }) -Tree 35: Descendants(Descendants { descendants: [5, 14, 19, 25, 30, 40, 41, 60, 72, 88, 91, 98] }) -Tree 36: Descendants(Descendants { descendants: [1, 2, 3, 10, 13, 26, 27, 36, 39, 42, 54, 57, 61, 62, 64, 65, 66, 68, 70, 79, 85, 87, 90, 95, 97] }) -Tree 37: SplitPlaneNormal(SplitPlaneNormal { left: 35, right: 36, normal: [-0.0634, 0.0493, -0.1593, 0.1795, 0.0751, -0.1612, 0.1902, 0.0103, -0.3135, 0.3654, "other ..."] }) -Tree 38: Descendants(Descendants { descendants: [0, 7, 9, 11, 15, 20, 29, 31, 32, 33, 35, 38, 44, 48, 49, 50, 63, 69, 75, 80, 83, 84, 94] }) -Tree 39: SplitPlaneNormal(SplitPlaneNormal { left: 37, right: 38, normal: [0.1761, -0.3237, -0.0771, 0.0829, 0.1048, -0.1838, -0.0306, 0.2495, -0.1249, -0.0092, "other ..."] }) -Tree 40: SplitPlaneNormal(SplitPlaneNormal { left: 34, right: 39, normal: [-0.2772, -0.1070, -0.0457, 0.1794, 0.1804, 0.1983, 0.0126, -0.2826, -0.2110, 0.1753, "other ..."] }) -Tree 41: Descendants(Descendants { descendants: [16, 22, 24, 34, 43, 45, 46, 51, 56, 58, 59, 76, 89, 92] }) -Tree 43: Descendants(Descendants { descendants: [8, 16, 21, 23, 28, 37, 43, 45, 46, 47, 54, 63, 66, 67, 68, 71, 72, 73, 78, 79, 80, 86, 91, 95] }) -Tree 44: Descendants(Descendants { descendants: [1, 2, 3, 6, 13, 26, 27, 29, 36, 40, 42, 44, 48, 50, 77, 81, 89, 90, 96, 97, 98, 99] }) -Tree 45: SplitPlaneNormal(SplitPlaneNormal { left: 43, right: 44, normal: [-0.3525, -0.1849, 0.2208, 0.2373, -0.0069, 0.1022, -0.1489, -0.0255, -0.0529, 0.1189, "other ..."] }) -Tree 46: Descendants(Descendants { descendants: [12, 19, 22, 24, 30, 31, 34, 41, 51, 56, 58, 59, 60, 61, 64, 76, 82, 83, 87, 92, 93] }) -Tree 47: Descendants(Descendants { descendants: [5, 7, 9, 10, 11, 14, 25, 33, 38, 39, 57, 62, 65, 70, 74, 85] }) -Tree 48: Descendants(Descendants { descendants: [0, 4, 15, 17, 18, 20, 32, 35, 49, 52, 53, 55, 69, 75, 84, 88, 94] }) -Tree 49: SplitPlaneNormal(SplitPlaneNormal { left: 47, right: 48, normal: [0.2088, -0.0636, -0.0548, 0.0285, 0.0978, -0.2930, 0.1189, 0.1050, 0.3094, -0.3048, "other ..."] }) -Tree 50: SplitPlaneNormal(SplitPlaneNormal { left: 46, right: 49, normal: [-0.1204, -0.0043, 0.1324, -0.1481, -0.0293, -0.3729, 0.1140, 0.3140, 0.2115, 0.2715, "other ..."] }) -Tree 52: Descendants(Descendants { descendants: [2, 4, 5, 17, 18, 25, 31, 32, 33, 35, 38, 49, 53, 55, 57, 59, 60, 67, 69, 73, 74, 75, 76, 84, 88, 94, 99] }) -Tree 53: Descendants(Descendants { descendants: [8, 12, 15, 20, 22, 23, 24, 34, 41, 43, 47, 51, 52, 56, 58, 61, 64, 68, 71, 78, 80, 82, 83, 87, 92] }) -Tree 54: SplitPlaneNormal(SplitPlaneNormal { left: 52, right: 53, normal: [0.3603, 0.0727, -0.1776, -0.1462, 0.0563, -0.1120, -0.3099, -0.1210, -0.0465, 0.0446, "other ..."] }) -Tree 55: Descendants(Descendants { descendants: [0, 3, 7, 9, 29, 48, 70, 81, 96, 97] }) -Tree 56: Descendants(Descendants { descendants: [13, 16, 19] }) -Tree 57: Descendants(Descendants { descendants: [11, 26, 27, 30, 36, 37, 39, 44, 45, 46, 50, 54, 62, 63, 65, 66, 72, 77, 79, 85, 86, 89, 90, 91, 93, 95, 98] }) -Tree 58: Descendants(Descendants { descendants: [1, 10, 14, 40, 42] }) -Tree 59: SplitPlaneNormal(SplitPlaneNormal { left: 57, right: 58, normal: [-0.4605, -0.0650, 0.1659, -0.0975, -0.0184, 0.0644, -0.2423, -0.1028, -0.0656, 0.0266, "other ..."] }) -Tree 60: SplitPlaneNormal(SplitPlaneNormal { left: 56, right: 59, normal: [0.2276, -0.1366, 0.1310, -0.1017, -0.2913, -0.0059, 0.1357, 0.4185, 0.1491, 0.2157, "other ..."] }) -Tree 61: Descendants(Descendants { descendants: [6, 21, 28] }) -Tree 62: SplitPlaneNormal(SplitPlaneNormal { left: 60, right: 61, normal: [0.4596, 0.0324, -0.1382, 0.0817, -0.0810, -0.2049, -0.0655, 0.1545, 0.0863, -0.1487, "other ..."] }) -Tree 63: SplitPlaneNormal(SplitPlaneNormal { left: 55, right: 62, normal: [0.1562, 0.0393, 0.1009, 0.1569, 0.0713, -0.1738, -0.1934, -0.3656, 0.0619, -0.2597, "other ..."] }) -Tree 65: Descendants(Descendants { descendants: [2, 4, 7, 10, 26, 27, 29, 31, 39, 57, 62, 65, 67, 70, 85, 86, 96, 97] }) -Tree 66: Descendants(Descendants { descendants: [13, 28, 30, 33, 36, 42, 45, 46, 50, 51, 56, 63, 66, 72, 89, 93] }) -Tree 67: SplitPlaneNormal(SplitPlaneNormal { left: 65, right: 66, normal: [0.2268, 0.1528, 0.0838, 0.2988, 0.1324, -0.0303, -0.3025, -0.1626, -0.1830, -0.3594, "other ..."] }) -Tree 68: Descendants(Descendants { descendants: [3, 15, 16, 17, 20, 22, 24, 38, 58, 59, 77, 80, 94] }) -Tree 69: Descendants(Descendants { descendants: [6, 8, 12, 18, 21, 23, 37, 41, 43, 47, 52, 53, 54, 55, 61, 64, 68, 71, 73, 78, 79, 83, 87, 90, 95] }) -Tree 70: SplitPlaneNormal(SplitPlaneNormal { left: 68, right: 69, normal: [0.2389, 0.1170, -0.4682, 0.0115, 0.1053, -0.1625, 0.1364, 0.0139, 0.2077, -0.2495, "other ..."] }) -Tree 71: SplitPlaneNormal(SplitPlaneNormal { left: 67, right: 70, normal: [0.0999, 0.1850, -0.1401, -0.1190, -0.1531, -0.1959, 0.0606, 0.0370, 0.3700, 0.1146, "other ..."] }) -Tree 72: Descendants(Descendants { descendants: [0, 1, 5, 9, 11, 14, 19, 25, 32, 34, 35, 40, 44, 48, 49, 60, 69, 74, 75, 76, 81, 82, 84, 88, 91, 92, 98, 99] }) -Tree 74: Descendants(Descendants { descendants: [20, 32, 35, 49, 53, 71, 74, 75, 82, 84, 88, 92, 99] }) -Tree 75: Descendants(Descendants { descendants: [22, 24, 38, 58, 76, 83, 94] }) -Tree 76: Descendants(Descendants { descendants: [4, 12, 15, 17, 18, 23, 41, 43, 47, 51, 54, 55, 57, 59, 60, 61, 64, 65, 68, 69, 77, 78, 79, 85] }) -Tree 77: SplitPlaneNormal(SplitPlaneNormal { left: 75, right: 76, normal: [0.1228, 0.1559, -0.1288, -0.2003, -0.1132, -0.1239, -0.1022, 0.1057, 0.4315, 0.0834, "other ..."] }) -Tree 78: Descendants(Descendants { descendants: [8, 37, 52, 73, 87] }) -Tree 79: SplitPlaneNormal(SplitPlaneNormal { left: 77, right: 78, normal: [0.0248, 0.0088, -0.0313, -0.1335, -0.1272, -0.3502, 0.0250, -0.0179, -0.1917, -0.0972, "other ..."] }) -Tree 80: SplitPlaneNormal(SplitPlaneNormal { left: 74, right: 79, normal: [0.0049, 0.2249, -0.1543, -0.0146, 0.2885, 0.3349, 0.0730, 0.0682, -0.0736, 0.0251, "other ..."] }) -Tree 81: Descendants(Descendants { descendants: [0, 11, 14, 33, 40, 42, 44, 50, 81, 89, 95] }) -Tree 82: Descendants(Descendants { descendants: [3, 5, 9, 13, 16, 19, 27, 30, 31, 39, 46, 56, 66, 67, 72, 80, 90, 91, 96, 97, 98] }) -Tree 83: SplitPlaneNormal(SplitPlaneNormal { left: 81, right: 82, normal: [0.0039, 0.2686, 0.2674, -0.2573, 0.1128, 0.1680, 0.0730, -0.1730, -0.1700, 0.2092, "other ..."] }) -Tree 84: Descendants(Descendants { descendants: [6, 21, 28, 36, 45, 63, 93] }) -Tree 85: SplitPlaneNormal(SplitPlaneNormal { left: 83, right: 84, normal: [0.1692, 0.0824, 0.0545, 0.1043, -0.0712, -0.1564, 0.1346, -0.2054, -0.3574, 0.0227, "other ..."] }) -Tree 86: Descendants(Descendants { descendants: [1, 2, 7, 10, 25, 26, 29, 34, 48, 62, 70, 86] }) -Tree 87: SplitPlaneNormal(SplitPlaneNormal { left: 85, right: 86, normal: [-0.1639, -0.0844, -0.0247, 0.0094, -0.2939, -0.0633, 0.1594, -0.0242, -0.2796, 0.0975, "other ..."] }) -Tree 89: Descendants(Descendants { descendants: [3, 5, 7, 9, 15, 23, 27, 29, 39, 46, 47, 57, 65, 66, 67, 72, 77, 80, 87, 96, 97] }) -Tree 90: Descendants(Descendants { descendants: [2, 6, 20, 26, 28, 33, 36, 38, 44, 45, 50, 54, 61, 63, 68, 79, 81, 82, 86, 88, 89, 94, 95, 99] }) -Tree 91: SplitPlaneNormal(SplitPlaneNormal { left: 89, right: 90, normal: [0.2298, -0.0543, -0.0903, 0.4705, -0.0333, -0.1476, 0.0085, -0.2924, -0.0262, -0.1555, "other ..."] }) -Tree 92: Descendants(Descendants { descendants: [13, 16, 21, 22, 24, 34, 43, 48, 56, 58, 59, 76, 78, 83, 93] }) -Tree 93: SplitPlaneNormal(SplitPlaneNormal { left: 91, right: 92, normal: [0.0186, -0.1006, -0.0831, -0.0214, -0.1000, 0.1422, -0.0251, -0.0633, -0.1181, -0.4053, "other ..."] }) -Tree 94: Descendants(Descendants { descendants: [1, 19, 62, 91] }) -Tree 95: Descendants(Descendants { descendants: [0, 4, 8, 12, 17, 18, 32, 35, 37, 49, 51, 52, 53, 55, 60, 64, 69, 71, 73, 74, 75, 84, 85] }) -Tree 96: Descendants(Descendants { descendants: [10, 11, 14, 25, 30, 31, 40, 41, 42, 70, 90, 92, 98] }) -Tree 97: SplitPlaneNormal(SplitPlaneNormal { left: 95, right: 96, normal: [0.0157, -0.0853, 0.0567, 0.1272, -0.0078, 0.2013, -0.2768, -0.2711, -0.0909, -0.2203, "other ..."] }) -Tree 98: SplitPlaneNormal(SplitPlaneNormal { left: 94, right: 97, normal: [0.0840, -0.0798, 0.1237, -0.0764, -0.0159, -0.2518, 0.3205, 0.2481, 0.0346, 0.0196, "other ..."] }) -Tree 100: Descendants(Descendants { descendants: [12, 15, 17, 18, 32, 37, 38, 47, 49, 53, 55, 57, 60, 61, 64, 65, 68, 69, 70, 73, 74, 75, 79, 84, 85, 87, 88, 94, 95, 99] }) -Tree 101: Descendants(Descendants { descendants: [0, 4, 7, 9, 31, 35, 52] }) -Tree 102: SplitPlaneNormal(SplitPlaneNormal { left: 100, right: 101, normal: [0.1985, -0.1880, 0.0307, -0.1037, -0.0564, -0.2396, -0.0511, 0.0306, -0.0198, -0.2910, "other ..."] }) -Tree 103: Descendants(Descendants { descendants: [5, 20, 22, 23, 24, 43, 58, 59, 71, 76, 78, 82, 83] }) -Tree 104: SplitPlaneNormal(SplitPlaneNormal { left: 102, right: 103, normal: [0.0471, -0.0086, -0.0301, -0.0896, -0.0916, 0.1329, -0.2187, -0.3051, 0.0333, -0.1385, "other ..."] }) -Tree 105: Descendants(Descendants { descendants: [8, 13, 14, 16, 19, 21, 25, 30, 34, 39, 40, 41, 42, 44, 46, 51, 56, 66, 67, 72, 80, 91, 92, 98] }) -Tree 106: Descendants(Descendants { descendants: [1, 2, 3, 6, 10, 11, 26, 27, 28, 29, 33, 36, 45, 48, 50, 54, 62, 63, 77, 81, 86, 89, 90, 93, 96, 97] }) -Tree 107: SplitPlaneNormal(SplitPlaneNormal { left: 105, right: 106, normal: [-0.0043, 0.0084, 0.0702, 0.2392, -0.0019, -0.2868, 0.1842, 0.1648, -0.2369, 0.4108, "other ..."] }) -Tree 109: Descendants(Descendants { descendants: [2, 7, 10, 11, 27, 70, 96, 97, 99] }) -Tree 110: Descendants(Descendants { descendants: [0, 5, 12, 14, 17, 19, 25, 33, 34, 35, 40, 44, 48, 49, 60, 69, 71, 74, 75, 81, 84, 88, 92, 98] }) -Tree 111: Descendants(Descendants { descendants: [9, 15, 20, 23, 24, 38, 53, 58, 59, 63, 65, 67, 82, 83, 87, 94] }) -Tree 112: SplitPlaneNormal(SplitPlaneNormal { left: 110, right: 111, normal: [0.2132, 0.0621, 0.0300, -0.2124, 0.1662, 0.0951, 0.0083, -0.0344, -0.1404, 0.3391, "other ..."] }) -Tree 113: Descendants(Descendants { descendants: [16, 29, 30, 31, 41, 43, 46, 50, 51, 56, 64, 72, 76, 78] }) -Tree 114: Descendants(Descendants { descendants: [3, 4, 8, 18, 21, 22, 32, 36, 37, 39, 47, 54, 55, 57, 61, 62, 66, 68, 73, 77, 79, 80, 85, 86, 93, 95] }) -Tree 115: SplitPlaneNormal(SplitPlaneNormal { left: 113, right: 114, normal: [0.0087, 0.0635, 0.0192, 0.0747, -0.2173, -0.3490, 0.0443, 0.1528, 0.1739, 0.3751, "other ..."] }) -Tree 116: SplitPlaneNormal(SplitPlaneNormal { left: 112, right: 115, normal: [0.1072, 0.2300, -0.0531, -0.0113, 0.0042, -0.0105, -0.0042, 0.1061, -0.1198, -0.1595, "other ..."] }) -Tree 117: SplitPlaneNormal(SplitPlaneNormal { left: 109, right: 116, normal: [0.0798, 0.0307, 0.0889, -0.0105, -0.1144, 0.2471, -0.0233, 0.0400, 0.1735, 0.0095, "other ..."] }) -Tree 118: Descendants(Descendants { descendants: [1, 6, 13, 26, 28, 42, 45, 52, 89, 90, 91] }) +Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 94, right: 95, normal: [-0.1046, -0.1048, -0.2896, 0.1156, 0.1824, 0.0581, 0.1255, -0.4503, -0.1752, -0.0560, "other ..."] }) +Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 86, right: 87, normal: [-0.2341, 0.1458, 0.0773, 0.1020, 0.0417, 0.2230, -0.1430, -0.2387, -0.3313, 0.1407, "other ..."] }) +Tree 2: SplitPlaneNormal(SplitPlaneNormal { left: 74, right: 77, normal: [0.1217, 0.0833, -0.0056, 0.1328, -0.0380, 0.0330, 0.0748, -0.2139, -0.0114, 0.2295, "other ..."] }) +Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 58, right: 67, normal: [0.2244, -0.0253, -0.2056, 0.0824, 0.2003, 0.0394, 0.0264, 0.0473, -0.1382, -0.0086, "other ..."] }) +Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 50, right: 57, normal: [-0.0984, -0.1910, 0.0089, -0.1606, -0.0976, 0.1223, 0.2206, 0.0719, -0.0332, -0.1140, "other ..."] }) +Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 46, right: 49, normal: [-0.0789, -0.0919, -0.2989, 0.0919, 0.1022, 0.0531, 0.1250, 0.1123, -0.2858, 0.1638, "other ..."] }) +Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 42, right: 43, normal: [0.0953, -0.3674, -0.1991, 0.1479, 0.1567, 0.2698, -0.0292, -0.4009, -0.2190, -0.2206, "other ..."] }) +Tree 7: SplitPlaneNormal(SplitPlaneNormal { left: 32, right: 35, normal: [0.0745, -0.0082, 0.0411, 0.0279, 0.1671, -0.0662, -0.1877, 0.0130, -0.1362, -0.1283, "other ..."] }) +Tree 8: SplitPlaneNormal(SplitPlaneNormal { left: 16, right: 27, normal: [-0.2393, 0.0454, 0.0895, -0.2982, -0.1505, 0.0530, 0.0785, 0.0330, 0.3852, 0.2541, "other ..."] }) +Tree 9: SplitPlaneNormal(SplitPlaneNormal { left: 14, right: 15, normal: [-0.3441, -0.2391, 0.1543, 0.1196, -0.1148, 0.1463, -0.0595, -0.2466, 0.0381, -0.0162, "other ..."] }) +Tree 10: Descendants(Descendants { descendants: [6, 7, 9, 12, 15, 17, 18, 20, 21, 22, 23, 37, 41, 43, 47, 52, 53, 55, 58, 59, 68, 71, 77, 79, 80, 86, 89, 93, 95] }) +Tree 11: Descendants(Descendants { descendants: [8, 16, 24, 46, 54, 66, 69, 78, 83, 87, 94, 98] }) +Tree 12: Descendants(Descendants { descendants: [3, 4, 11, 13, 27, 28, 29, 30, 31, 35, 36, 39, 45, 50, 51, 56, 57, 61, 63, 64, 65, 67, 72, 73, 85, 90, 91, 96, 97] }) +Tree 13: SplitPlaneNormal(SplitPlaneNormal { left: 11, right: 12, normal: [-0.1005, -0.1220, 0.0732, -0.0179, 0.2045, -0.0018, -0.1563, 0.1334, -0.0829, 0.1324, "other ..."] }) +Tree 14: SplitPlaneNormal(SplitPlaneNormal { left: 10, right: 13, normal: [-0.1772, -0.0157, -0.0850, 0.1352, 0.2172, 0.3184, -0.0247, -0.2431, -0.1115, -0.1358, "other ..."] }) +Tree 15: Descendants(Descendants { descendants: [0, 1, 2, 5, 10, 14, 19, 25, 26, 32, 33, 34, 38, 40, 42, 44, 48, 49, 60, 62, 70, 74, 75, 76, 81, 82, 84, 88, 92, 99] }) +Tree 16: Descendants(Descendants { descendants: [1, 13, 21, 28, 29, 36, 45, 48, 50, 54, 63, 76, 89, 90, 93] }) +Tree 17: Descendants(Descendants { descendants: [8, 22, 23, 27, 37, 43, 47, 55, 60, 68, 71, 73, 74, 81, 87, 95, 96, 99] }) +Tree 18: Descendants(Descendants { descendants: [3, 7, 15, 17, 18, 20, 32, 38, 52, 53, 57, 58, 69, 75, 77, 79, 82, 88, 94] }) +Tree 19: SplitPlaneNormal(SplitPlaneNormal { left: 17, right: 18, normal: [-0.1772, -0.2198, 0.2474, 0.1118, -0.0456, 0.1362, -0.1257, 0.1055, 0.1471, 0.1266, "other ..."] }) +Tree 20: Descendants(Descendants { descendants: [6, 11, 14, 26, 62, 86, 91] }) +Tree 21: SplitPlaneNormal(SplitPlaneNormal { left: 19, right: 20, normal: [-0.0556, -0.0865, 0.0697, 0.2287, -0.1149, -0.0734, -0.0678, -0.1608, 0.0585, -0.2476, "other ..."] }) +Tree 22: Descendants(Descendants { descendants: [5, 16, 24, 40, 41, 51, 56, 61, 78, 83] }) +Tree 23: Descendants(Descendants { descendants: [0, 2, 4, 9, 10, 12, 19, 30, 31, 33, 35, 39, 42, 44, 46, 59, 64, 65, 66, 67, 70, 72, 80, 85, 97, 98] }) +Tree 24: SplitPlaneNormal(SplitPlaneNormal { left: 22, right: 23, normal: [0.1479, -0.0104, 0.2355, 0.0980, 0.1720, -0.2055, 0.0480, 0.1973, -0.0260, 0.0884, "other ..."] }) +Tree 25: Descendants(Descendants { descendants: [25, 34, 49, 84, 92] }) +Tree 26: SplitPlaneNormal(SplitPlaneNormal { left: 24, right: 25, normal: [-0.0980, -0.3348, -0.0687, 0.0361, -0.2066, -0.1423, 0.0663, -0.0771, -0.1621, -0.1077, "other ..."] }) +Tree 27: SplitPlaneNormal(SplitPlaneNormal { left: 21, right: 26, normal: [-0.2059, -0.2478, 0.0146, -0.1079, 0.1970, 0.2143, -0.0704, -0.1705, -0.1067, -0.2651, "other ..."] }) +Tree 28: Descendants(Descendants { descendants: [2, 7, 8, 9, 18, 21, 23, 43, 47, 52, 53, 55, 56, 61, 64, 68, 69, 70, 71, 72, 78, 80, 81, 86, 87] }) +Tree 29: Descendants(Descendants { descendants: [3, 15, 17, 20, 22, 24, 26, 32, 33, 38, 48, 57, 58, 75, 77, 79, 82, 83, 94, 95] }) +Tree 30: SplitPlaneNormal(SplitPlaneNormal { left: 28, right: 29, normal: [0.0649, -0.2817, 0.1308, 0.1750, -0.1072, 0.0739, -0.0655, -0.0820, -0.0308, 0.1929, "other ..."] }) +Tree 31: Descendants(Descendants { descendants: [0, 5, 12, 14, 16, 19, 25, 31, 34, 35, 40, 41, 44, 49, 51, 59, 60, 74, 76, 84, 88, 92, 98, 99] }) +Tree 32: SplitPlaneNormal(SplitPlaneNormal { left: 30, right: 31, normal: [-0.0995, -0.3281, 0.1549, 0.1141, -0.1495, 0.0941, -0.0629, -0.1079, 0.0170, -0.4129, "other ..."] }) +Tree 33: Descendants(Descendants { descendants: [1, 10, 13, 30, 37, 39, 42, 46, 54, 62, 66, 85, 89, 90, 91, 93] }) +Tree 34: Descendants(Descendants { descendants: [4, 6, 11, 27, 28, 29, 36, 45, 50, 63, 65, 67, 73, 96, 97] }) +Tree 35: SplitPlaneNormal(SplitPlaneNormal { left: 33, right: 34, normal: [0.0991, -0.0790, -0.0159, -0.0262, 0.3599, 0.0632, 0.0606, 0.1342, -0.2027, 0.1665, "other ..."] }) +Tree 36: Descendants(Descendants { descendants: [3, 6, 26, 27, 28, 36, 37, 38, 57, 62, 65, 68, 77, 79, 85, 91, 95, 96] }) +Tree 37: Descendants(Descendants { descendants: [1, 16, 20, 21, 22, 43, 45, 47, 50, 54, 66, 73, 80, 90, 93, 94] }) +Tree 38: SplitPlaneNormal(SplitPlaneNormal { left: 36, right: 37, normal: [0.1676, -0.0197, 0.0170, -0.1107, -0.0617, -0.1744, -0.0523, 0.0242, -0.2194, -0.3968, "other ..."] }) +Tree 39: Descendants(Descendants { descendants: [5, 8, 12, 15, 17, 18, 23, 32, 52, 53, 55, 64, 69, 71, 74, 75, 78, 81, 82, 87, 88, 99] }) +Tree 40: Descendants(Descendants { descendants: [0, 2, 4, 7, 9, 10, 11, 14, 19, 25, 29, 30, 35, 39, 40, 42, 44, 46, 61, 67, 70, 72, 86, 89, 97, 98] }) +Tree 41: SplitPlaneNormal(SplitPlaneNormal { left: 39, right: 40, normal: [-0.0869, -0.1012, -0.0140, 0.0978, 0.2072, 0.3786, -0.1467, -0.0113, -0.1416, -0.1981, "other ..."] }) +Tree 42: SplitPlaneNormal(SplitPlaneNormal { left: 38, right: 41, normal: [0.1020, -0.2572, -0.0377, -0.1376, 0.0667, -0.0283, 0.0005, 0.1117, 0.0582, -0.2710, "other ..."] }) +Tree 43: Descendants(Descendants { descendants: [13, 24, 31, 33, 34, 41, 48, 49, 51, 56, 58, 59, 60, 63, 76, 83, 84, 92] }) +Tree 44: Descendants(Descendants { descendants: [5, 8, 12, 17, 19, 40, 41, 49, 52, 53, 59, 60, 64, 75, 81, 82, 88, 92, 98, 99] }) +Tree 45: Descendants(Descendants { descendants: [6, 15, 16, 18, 21, 22, 23, 24, 43, 46, 54, 55, 56, 66, 67, 71, 72, 73, 77, 78, 80, 87, 91, 94] }) +Tree 46: SplitPlaneNormal(SplitPlaneNormal { left: 44, right: 45, normal: [0.2662, 0.3014, 0.0478, -0.2119, 0.0998, -0.0888, -0.0532, 0.0641, -0.1842, 0.0472, "other ..."] }) +Tree 47: Descendants(Descendants { descendants: [1, 3, 4, 10, 11, 13, 27, 28, 29, 30, 36, 37, 39, 42, 45, 50, 51, 57, 62, 63, 65, 85, 89, 90, 93, 96, 97] }) +Tree 48: Descendants(Descendants { descendants: [0, 2, 7, 9, 14, 20, 25, 26, 31, 32, 33, 34, 35, 38, 44, 47, 48, 58, 61, 68, 69, 70, 74, 76, 79, 83, 84, 86, 95] }) +Tree 49: SplitPlaneNormal(SplitPlaneNormal { left: 47, right: 48, normal: [0.0061, 0.0458, -0.1585, 0.0051, -0.1846, 0.2038, 0.1001, 0.1499, 0.1651, -0.0044, "other ..."] }) +Tree 50: Descendants(Descendants { descendants: [6, 7, 9, 14, 19, 23, 26, 27, 28, 40, 42, 45, 48, 52, 68, 81, 86, 95, 96] }) +Tree 51: Descendants(Descendants { descendants: [8, 10, 13, 30, 44, 46, 51, 61, 64, 67, 72, 73, 78, 83, 87] }) +Tree 52: Descendants(Descendants { descendants: [0, 1, 2, 3, 4, 11, 25, 29, 31, 32, 33, 35, 36, 38, 39, 50, 56, 57, 62, 65, 70, 74, 77, 85, 89, 90, 93, 97] }) +Tree 53: Descendants(Descendants { descendants: [5, 12, 15, 16, 18, 20, 22, 24, 34, 43, 47, 49, 54, 58, 59, 63, 66, 69, 75, 76, 80, 84, 88, 92, 94, 98, 99] }) +Tree 54: SplitPlaneNormal(SplitPlaneNormal { left: 52, right: 53, normal: [0.0922, 0.1506, 0.1227, 0.0115, 0.1046, -0.0041, 0.0193, -0.1702, 0.0036, 0.0171, "other ..."] }) +Tree 55: Descendants(Descendants { descendants: [17, 21, 37, 41, 53, 55, 60, 71, 79, 82, 91] }) +Tree 56: SplitPlaneNormal(SplitPlaneNormal { left: 54, right: 55, normal: [-0.0376, 0.0783, -0.1737, -0.1964, -0.2991, -0.1252, 0.0759, -0.0757, 0.4579, -0.0415, "other ..."] }) +Tree 57: SplitPlaneNormal(SplitPlaneNormal { left: 51, right: 56, normal: [0.1959, -0.0521, 0.4353, 0.1663, -0.4041, -0.1843, -0.0176, 0.1009, -0.0109, 0.1246, "other ..."] }) +Tree 58: Descendants(Descendants { descendants: [2, 5, 14, 17, 25, 40, 42, 49, 60, 71, 75, 81, 84, 88, 98, 99] }) +Tree 59: Descendants(Descendants { descendants: [16, 27, 28, 37, 54, 73, 91] }) +Tree 60: Descendants(Descendants { descendants: [0, 1, 7, 9, 10, 11, 29, 38, 48, 65, 69, 70, 74, 76, 83, 94, 97] }) +Tree 61: Descendants(Descendants { descendants: [6, 20, 21, 22, 26, 31, 32, 33, 34, 36, 39, 43, 44, 45, 50, 55, 58, 62, 63, 66, 79, 80, 86, 89, 90, 92, 93, 95, 96] }) +Tree 62: Descendants(Descendants { descendants: [3, 4, 8, 12, 15, 18, 19, 23, 35, 41, 47, 51, 52, 53, 56, 57, 59, 61, 64, 67, 68, 77, 82, 85, 87] }) +Tree 63: SplitPlaneNormal(SplitPlaneNormal { left: 61, right: 62, normal: [-0.2559, -0.1015, -0.2100, -0.3536, 0.1293, 0.1860, 0.0816, 0.1475, 0.3886, -0.0411, "other ..."] }) +Tree 64: Descendants(Descendants { descendants: [13, 24, 30, 46, 72, 78] }) +Tree 65: SplitPlaneNormal(SplitPlaneNormal { left: 63, right: 64, normal: [-0.3508, 0.1370, -0.2724, -0.1489, 0.1038, 0.0956, -0.2250, -0.0055, 0.0409, -0.0618, "other ..."] }) +Tree 66: SplitPlaneNormal(SplitPlaneNormal { left: 60, right: 65, normal: [0.0746, 0.1798, 0.1707, 0.0568, -0.0043, -0.0352, -0.2617, -0.1400, 0.0376, -0.1896, "other ..."] }) +Tree 67: SplitPlaneNormal(SplitPlaneNormal { left: 59, right: 66, normal: [0.0678, -0.1792, 0.0873, -0.0232, 0.0879, -0.0526, 0.0465, 0.2410, 0.0000, -0.1470, "other ..."] }) +Tree 68: Descendants(Descendants { descendants: [0, 1, 2, 3, 4, 5, 7, 9, 10, 11, 14, 17, 25, 26, 27, 29, 33, 48, 55, 62, 65, 69, 70, 73, 74, 84, 86, 96, 97] }) +Tree 69: Descendants(Descendants { descendants: [28, 37] }) +Tree 70: Descendants(Descendants { descendants: [8, 13, 18, 32, 36, 39, 45, 50, 51, 56, 57, 61, 64, 67, 76, 77, 80, 85, 89, 90, 93, 95] }) +Tree 71: Descendants(Descendants { descendants: [19, 30, 31, 35, 40, 41, 42, 44, 46, 52, 66, 72, 91, 92, 98] }) +Tree 72: SplitPlaneNormal(SplitPlaneNormal { left: 70, right: 71, normal: [-0.0311, -0.0765, -0.0680, -0.0559, 0.0108, 0.1307, -0.1805, -0.2474, 0.2281, -0.0971, "other ..."] }) +Tree 73: SplitPlaneNormal(SplitPlaneNormal { left: 69, right: 72, normal: [0.0581, -0.2523, 0.4058, -0.0309, -0.1815, 0.1999, 0.0743, -0.0071, -0.1380, -0.1659, "other ..."] }) +Tree 74: SplitPlaneNormal(SplitPlaneNormal { left: 68, right: 73, normal: [0.0363, -0.0129, -0.1424, 0.1457, 0.1532, 0.0220, -0.0942, -0.2280, 0.1921, -0.3136, "other ..."] }) +Tree 75: Descendants(Descendants { descendants: [6, 21, 23, 43, 47, 68, 81, 99] }) +Tree 76: Descendants(Descendants { descendants: [12, 15, 16, 20, 22, 24, 34, 38, 49, 53, 54, 58, 59, 60, 63, 71, 75, 78, 79, 82, 83, 87, 88, 94] }) +Tree 77: SplitPlaneNormal(SplitPlaneNormal { left: 75, right: 76, normal: [-0.2100, -0.3231, 0.0075, -0.1781, 0.0097, 0.1887, 0.3090, 0.0374, -0.1285, 0.0167, "other ..."] }) +Tree 78: Descendants(Descendants { descendants: [6, 8, 16, 19, 21, 23, 24, 37, 47, 54, 60, 61, 63, 64, 68, 73, 77, 78, 87] }) +Tree 79: Descendants(Descendants { descendants: [0, 2, 4, 5, 7, 9, 11, 14, 15, 17, 18, 33, 35, 39, 46, 52, 53, 67, 69, 71, 72, 74, 75, 81, 83, 86, 98, 99] }) +Tree 80: Descendants(Descendants { descendants: [12, 25, 34, 40, 44, 48, 92] }) +Tree 81: SplitPlaneNormal(SplitPlaneNormal { left: 79, right: 80, normal: [-0.1575, -0.1128, -0.1122, 0.1065, -0.2140, 0.1280, -0.0397, -0.3964, -0.2684, -0.0552, "other ..."] }) +Tree 82: Descendants(Descendants { descendants: [20, 22, 31, 32, 41, 43, 50, 51, 55, 56, 57, 58, 59, 70, 76, 79, 80, 82, 89, 90, 94, 95] }) +Tree 83: SplitPlaneNormal(SplitPlaneNormal { left: 81, right: 82, normal: [0.0635, -0.1193, -0.0125, 0.0744, 0.0352, 0.0352, 0.0132, -0.1754, -0.1790, 0.0519, "other ..."] }) +Tree 84: Descendants(Descendants { descendants: [38, 49, 84, 88] }) +Tree 85: SplitPlaneNormal(SplitPlaneNormal { left: 83, right: 84, normal: [-0.3818, 0.0535, 0.0658, -0.0525, -0.0179, 0.1437, 0.2199, -0.1148, -0.0230, 0.3660, "other ..."] }) +Tree 86: SplitPlaneNormal(SplitPlaneNormal { left: 78, right: 85, normal: [0.1310, -0.2508, 0.2970, -0.0137, -0.1836, -0.1572, 0.0576, 0.0822, -0.1664, -0.1609, "other ..."] }) +Tree 87: Descendants(Descendants { descendants: [1, 3, 10, 13, 26, 27, 28, 29, 30, 36, 42, 45, 62, 65, 66, 85, 91, 93, 96, 97] }) +Tree 88: Descendants(Descendants { descendants: [2, 6, 7, 11, 14, 17, 26, 27, 28, 33, 34, 36, 40, 42, 56, 62, 66, 67, 86, 91, 93, 96, 97] }) +Tree 89: Descendants(Descendants { descendants: [0, 18, 25, 32, 35, 49, 55, 57, 61, 69, 72, 84, 89, 90, 98] }) +Tree 90: Descendants(Descendants { descendants: [1, 3, 4, 5, 9, 10, 29, 30, 31, 39, 44, 50, 65, 70, 74, 85] }) +Tree 91: SplitPlaneNormal(SplitPlaneNormal { left: 89, right: 90, normal: [0.1694, 0.0543, -0.0064, -0.1514, 0.1012, 0.1969, -0.0638, 0.0336, -0.5388, 0.1582, "other ..."] }) +Tree 92: SplitPlaneNormal(SplitPlaneNormal { left: 88, right: 91, normal: [-0.1385, -0.2610, -0.3148, -0.2565, 0.0517, -0.0217, 0.3147, 0.2264, 0.0398, 0.1033, "other ..."] }) +Tree 93: Descendants(Descendants { descendants: [8, 15, 20, 21, 22, 23, 37, 41, 46, 47, 52, 53, 54, 59, 71, 73, 77, 78, 79, 80, 81, 82, 94, 95, 99] }) +Tree 94: SplitPlaneNormal(SplitPlaneNormal { left: 92, right: 93, normal: [0.4416, 0.0529, -0.2415, 0.0425, -0.0870, -0.2230, -0.0310, -0.0219, 0.1446, -0.1358, "other ..."] }) +Tree 95: Descendants(Descendants { descendants: [12, 13, 16, 19, 24, 38, 43, 45, 48, 51, 58, 60, 63, 64, 68, 75, 76, 83, 87, 88, 92] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.8013, 0.2371, 0.6955, 0.8606, 0.5280, 0.2667, 0.6057, 0.9830, 0.9430, 0.0479, "other ..."] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.4199, 0.2620, 0.2655, 0.8414, 0.0192, 0.3828, 0.2561, 0.2692, 0.0368, 0.4624, "other ..."] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.1040, 0.9647, 0.8238, 0.5344, 0.4903, 0.4420, 0.7937, 0.4028, 0.2083, 0.3315, "other ..."] }) diff --git a/src/tests/writer.rs b/src/tests/writer.rs index 8f14a7e..e8bd8f7 100644 --- a/src/tests/writer.rs +++ b/src/tests/writer.rs @@ -281,9 +281,9 @@ fn write_vectors_until_there_is_a_split() { Dumping index 0 Root: Metadata { dimensions: 3, items: RoaringBitmap<[0, 1, 2, 3]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: [0.5774, 0.5774, 0.5774] }) - Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: Descendants(Descendants { descendants: [1, 2, 3] }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: "none" }) + Tree 1: Descendants(Descendants { descendants: [2, 3] }) + Tree 2: Descendants(Descendants { descendants: [0, 1] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [1.0000, 1.0000, 1.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [2.0000, 2.0000, 2.0000] }) @@ -407,8 +407,8 @@ fn overwrite_one_item_incremental() { Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 6, normal: [1.0000, 0.0000] }) Tree 1: Descendants(Descendants { descendants: [0] }) Tree 2: Descendants(Descendants { descendants: [1, 5] }) - Tree 3: Descendants(Descendants { descendants: [3, 4] }) - Tree 4: Descendants(Descendants { descendants: [2] }) + Tree 3: Descendants(Descendants { descendants: [4] }) + Tree 4: Descendants(Descendants { descendants: [2, 3] }) Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 5, normal: "none" }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) @@ -438,8 +438,8 @@ fn overwrite_one_item_incremental() { Tree 2: Descendants(Descendants { descendants: [1, 5] }) Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 7, right: 8, normal: "none" }) Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 5, normal: "none" }) - Tree 7: Descendants(Descendants { descendants: [3, 4] }) - Tree 8: Descendants(Descendants { descendants: [2] }) + Tree 7: Descendants(Descendants { descendants: [3] }) + Tree 8: Descendants(Descendants { descendants: [2, 4] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [2.0000, 0.0000] }) @@ -606,9 +606,9 @@ fn delete_one_leaf_in_a_split() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: "none" }) - Tree 1: Descendants(Descendants { descendants: [1] }) - Tree 2: Descendants(Descendants { descendants: [0, 2] }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: [-1.0000, 0.0000] }) + Tree 1: Descendants(Descendants { descendants: [1, 2] }) + Tree 2: Descendants(Descendants { descendants: [0] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [2.0000, 0.0000] }) @@ -693,8 +693,8 @@ fn delete_one_item() { Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 6, normal: [1.0000, 0.0000] }) Tree 1: Descendants(Descendants { descendants: [0] }) Tree 2: Descendants(Descendants { descendants: [1, 5] }) - Tree 3: Descendants(Descendants { descendants: [3, 4] }) - Tree 4: Descendants(Descendants { descendants: [2] }) + Tree 3: Descendants(Descendants { descendants: [4] }) + Tree 4: Descendants(Descendants { descendants: [2, 3] }) Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 5, normal: "none" }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) @@ -856,9 +856,9 @@ fn add_one_item_incrementally_to_create_a_split_node() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: [-1.0000, 0.0000] }) - Tree 1: Descendants(Descendants { descendants: [1, 2] }) - Tree 2: Descendants(Descendants { descendants: [0] }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: [1.0000, 0.0000] }) + Tree 1: Descendants(Descendants { descendants: [0] }) + Tree 2: Descendants(Descendants { descendants: [1, 2] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [2.0000, 0.0000] }) @@ -886,8 +886,8 @@ fn add_one_item_incrementally() { Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 6, normal: [1.0000, 0.0000] }) Tree 1: Descendants(Descendants { descendants: [0] }) Tree 2: Descendants(Descendants { descendants: [1, 5] }) - Tree 3: Descendants(Descendants { descendants: [3, 4] }) - Tree 4: Descendants(Descendants { descendants: [2] }) + Tree 3: Descendants(Descendants { descendants: [4] }) + Tree 4: Descendants(Descendants { descendants: [2, 3] }) Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 5, normal: "none" }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) @@ -914,12 +914,12 @@ fn add_one_item_incrementally() { Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 6, normal: [1.0000, 0.0000] }) Tree 1: Descendants(Descendants { descendants: [0] }) Tree 2: Descendants(Descendants { descendants: [1, 5] }) - Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 7, right: 8, normal: "none" }) - Tree 4: Descendants(Descendants { descendants: [2] }) + Tree 3: Descendants(Descendants { descendants: [4] }) + Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 7, right: 8, normal: "none" }) Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 5, normal: "none" }) - Tree 7: Descendants(Descendants { descendants: [4, 25] }) - Tree 8: Descendants(Descendants { descendants: [3] }) + Tree 7: Descendants(Descendants { descendants: [3] }) + Tree 8: Descendants(Descendants { descendants: [2, 25] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [2.0000, 0.0000] }) @@ -944,15 +944,13 @@ fn add_one_item_incrementally() { Version: Version { major: 0, minor: 7, patch: 0 } Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 6, normal: [1.0000, 0.0000] }) Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: SplitPlaneNormal(SplitPlaneNormal { left: 9, right: 10, normal: "none" }) - Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 7, right: 8, normal: "none" }) - Tree 4: Descendants(Descendants { descendants: [2] }) + Tree 2: Descendants(Descendants { descendants: [1, 5] }) + Tree 3: Descendants(Descendants { descendants: [4] }) + Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 7, right: 8, normal: "none" }) Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 5, normal: "none" }) - Tree 7: Descendants(Descendants { descendants: [4, 25] }) - Tree 8: Descendants(Descendants { descendants: [3] }) - Tree 9: Descendants(Descendants { descendants: [8] }) - Tree 10: Descendants(Descendants { descendants: [1, 5] }) + Tree 7: Descendants(Descendants { descendants: [3, 8] }) + Tree 8: Descendants(Descendants { descendants: [2, 25] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [2.0000, 0.0000] }) @@ -983,12 +981,12 @@ fn delete_extraneous_tree() { Dumping index 0 Root: Metadata { dimensions: 4, items: RoaringBitmap<[0, 1, 2, 3, 4]>, roots: [0, 1], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 3, normal: [-1.0000, 0.0000, 0.0000, 0.0000] }) - Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 5, right: 6, normal: [1.0000, 0.0000, 0.0000, 0.0000] }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: [1.0000, 0.0000, 0.0000, 0.0000] }) + Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 3, normal: [-1.0000, 0.0000, 0.0000, 0.0000] }) Tree 2: Descendants(Descendants { descendants: [1, 2, 3, 4] }) Tree 3: Descendants(Descendants { descendants: [0] }) - Tree 5: Descendants(Descendants { descendants: [0] }) - Tree 6: Descendants(Descendants { descendants: [1, 2, 3, 4] }) + Tree 4: Descendants(Descendants { descendants: [0] }) + Tree 5: Descendants(Descendants { descendants: [1, 2, 3, 4] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000, 0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [1.0000, 0.0000, 0.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [2.0000, 0.0000, 0.0000, 0.0000] }) @@ -1006,12 +1004,12 @@ fn delete_extraneous_tree() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 4]>, roots: [0, 1], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 3, normal: [-1.0000, 0.0000, 0.0000, 0.0000] }) - Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 5, right: 6, normal: [1.0000, 0.0000, 0.0000, 0.0000] }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: [1.0000, 0.0000, 0.0000, 0.0000] }) + Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 3, normal: [-1.0000, 0.0000, 0.0000, 0.0000] }) Tree 2: Descendants(Descendants { descendants: [1, 2, 3, 4] }) Tree 3: Descendants(Descendants { descendants: [0] }) - Tree 5: Descendants(Descendants { descendants: [0] }) - Tree 6: Descendants(Descendants { descendants: [1, 2, 3, 4] }) + Tree 4: Descendants(Descendants { descendants: [0] }) + Tree 5: Descendants(Descendants { descendants: [1, 2, 3, 4] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000, 0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [1.0000, 0.0000, 0.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [2.0000, 0.0000, 0.0000, 0.0000] }) @@ -1029,9 +1027,9 @@ fn delete_extraneous_tree() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 4]>, roots: [1], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 5, right: 6, normal: [1.0000, 0.0000, 0.0000, 0.0000] }) - Tree 5: Descendants(Descendants { descendants: [0] }) - Tree 6: Descendants(Descendants { descendants: [1, 2, 3, 4] }) + Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 3, normal: [-1.0000, 0.0000, 0.0000, 0.0000] }) + Tree 2: Descendants(Descendants { descendants: [1, 2, 3, 4] }) + Tree 3: Descendants(Descendants { descendants: [0] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000, 0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [1.0000, 0.0000, 0.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [2.0000, 0.0000, 0.0000, 0.0000] }) @@ -1062,8 +1060,8 @@ fn create_root_split_node_with_empty_child() { Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 6, normal: [1.0000, 0.0000] }) Tree 1: Descendants(Descendants { descendants: [0] }) Tree 2: Descendants(Descendants { descendants: [1, 5] }) - Tree 3: Descendants(Descendants { descendants: [3, 4] }) - Tree 4: Descendants(Descendants { descendants: [2] }) + Tree 3: Descendants(Descendants { descendants: [4] }) + Tree 4: Descendants(Descendants { descendants: [2, 3] }) Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 5, normal: "none" }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) @@ -1090,8 +1088,8 @@ fn create_root_split_node_with_empty_child() { Version: Version { major: 0, minor: 7, patch: 0 } Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 5, normal: [1.0000, 0.0000] }) Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 3: Descendants(Descendants { descendants: [3, 4] }) - Tree 4: Descendants(Descendants { descendants: [2] }) + Tree 3: Descendants(Descendants { descendants: [4] }) + Tree 4: Descendants(Descendants { descendants: [2, 3] }) Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [2.0000, 0.0000] }) @@ -1112,8 +1110,8 @@ fn create_root_split_node_with_empty_child() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[2, 3, 4]>, roots: [5], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 3: Descendants(Descendants { descendants: [3, 4] }) - Tree 4: Descendants(Descendants { descendants: [2] }) + Tree 3: Descendants(Descendants { descendants: [4] }) + Tree 4: Descendants(Descendants { descendants: [2, 3] }) Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [2.0000, 0.0000] }) Item 3: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [3.0000, 0.0000] }) @@ -1142,8 +1140,8 @@ fn reuse_node_id() { Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 6, normal: [1.0000, 0.0000] }) Tree 1: Descendants(Descendants { descendants: [0] }) Tree 2: Descendants(Descendants { descendants: [1, 5] }) - Tree 3: Descendants(Descendants { descendants: [3, 4] }) - Tree 4: Descendants(Descendants { descendants: [2] }) + Tree 3: Descendants(Descendants { descendants: [4] }) + Tree 4: Descendants(Descendants { descendants: [2, 3] }) Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 5, normal: "none" }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) @@ -1195,10 +1193,10 @@ fn reuse_node_id() { Version: Version { major: 0, minor: 7, patch: 0 } Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 6, normal: [1.0000, 0.0000] }) Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) - Tree 3: Descendants(Descendants { descendants: [4, 5] }) - Tree 4: Descendants(Descendants { descendants: [1] }) - Tree 5: Descendants(Descendants { descendants: [2, 3] }) + Tree 2: Descendants(Descendants { descendants: [1, 5] }) + Tree 3: Descendants(Descendants { descendants: [3] }) + Tree 4: Descendants(Descendants { descendants: [2, 4] }) + Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 5, normal: "none" }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [1.0000, 0.0000] }) @@ -1222,18 +1220,18 @@ fn reuse_node_id() { Version: Version { major: 0, minor: 7, patch: 0 } Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 6, normal: [1.0000, 0.0000] }) Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) - Tree 3: Descendants(Descendants { descendants: [4, 5] }) - Tree 4: Descendants(Descendants { descendants: [1] }) - Tree 5: Descendants(Descendants { descendants: [2, 3] }) + Tree 2: Descendants(Descendants { descendants: [1, 5] }) + Tree 3: Descendants(Descendants { descendants: [3] }) + Tree 4: Descendants(Descendants { descendants: [2, 4] }) + Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 5, normal: "none" }) Tree 7: SplitPlaneNormal(SplitPlaneNormal { left: 14, right: 15, normal: [-1.0000, 0.0000] }) - Tree 8: Descendants(Descendants { descendants: [2] }) - Tree 9: Descendants(Descendants { descendants: [4, 5] }) - Tree 10: SplitPlaneNormal(SplitPlaneNormal { left: 8, right: 9, normal: "none" }) - Tree 11: Descendants(Descendants { descendants: [] }) - Tree 12: SplitPlaneNormal(SplitPlaneNormal { left: 10, right: 11, normal: "none" }) - Tree 13: Descendants(Descendants { descendants: [1, 3] }) + Tree 8: Descendants(Descendants { descendants: [1] }) + Tree 9: Descendants(Descendants { descendants: [5] }) + Tree 10: Descendants(Descendants { descendants: [3, 4] }) + Tree 11: SplitPlaneNormal(SplitPlaneNormal { left: 9, right: 10, normal: "none" }) + Tree 12: SplitPlaneNormal(SplitPlaneNormal { left: 8, right: 11, normal: "none" }) + Tree 13: Descendants(Descendants { descendants: [2] }) Tree 14: SplitPlaneNormal(SplitPlaneNormal { left: 12, right: 13, normal: "none" }) Tree 15: Descendants(Descendants { descendants: [0] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) diff --git a/src/unaligned_vector/binary_quantized.rs b/src/unaligned_vector/binary_quantized.rs index d4f4f29..d373e9a 100644 --- a/src/unaligned_vector/binary_quantized.rs +++ b/src/unaligned_vector/binary_quantized.rs @@ -71,6 +71,10 @@ impl UnalignedVectorCodec for BinaryQuantized { fn is_zero(vec: &UnalignedVector) -> bool { vec.as_bytes().iter().all(|b| *b == 0) } + + fn size_of_item(dimensions: usize) -> usize { + dimensions / QUANTIZED_WORD_BITS + } } pub(super) fn from_slice_non_optimized(slice: &[f32]) -> Vec { diff --git a/src/unaligned_vector/f32.rs b/src/unaligned_vector/f32.rs index aa078de..274642f 100644 --- a/src/unaligned_vector/f32.rs +++ b/src/unaligned_vector/f32.rs @@ -54,4 +54,8 @@ impl UnalignedVectorCodec for f32 { fn is_zero(vec: &UnalignedVector) -> bool { vec.iter().all(|v| v == 0.0) } + + fn size_of_item(dimensions: usize) -> usize { + dimensions * size_of::() + } } diff --git a/src/unaligned_vector/mod.rs b/src/unaligned_vector/mod.rs index 1b58739..1e6df85 100644 --- a/src/unaligned_vector/mod.rs +++ b/src/unaligned_vector/mod.rs @@ -43,6 +43,9 @@ pub trait UnalignedVectorCodec: std::borrow::ToOwned + Sized { /// Returns true if all the elements in the vector are equal to 0. fn is_zero(vec: &UnalignedVector) -> bool; + + /// Returns the size of an item in bytes. + fn size_of_item(dimensions: usize) -> usize; } /// A wrapper struct that is used to read unaligned vectors directly from memory. diff --git a/src/writer.rs b/src/writer.rs index 2f656a9..b94fde7 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1,5 +1,6 @@ use std::any::TypeId; use std::borrow::Cow; +use std::cell::RefCell; use std::path::PathBuf; use std::sync::atomic::AtomicU32; use std::sync::Arc; @@ -7,10 +8,12 @@ use std::sync::Arc; use heed::types::{Bytes, DecodeIgnore, Unit}; use heed::{MdbError, PutFlags, RoTxn, RwTxn}; use nohash::{BuildNoHashHasher, IntMap}; +use rand::rngs::StdRng; use rand::{Rng, SeedableRng}; use rayon::iter::repeatn; -use rayon::prelude::*; +use rayon::{current_num_threads, prelude::*, Scope}; use roaring::RoaringBitmap; +use thread_local::ThreadLocal; use crate::distance::Distance; use crate::internals::{KeyCodec, Side}; @@ -28,7 +31,7 @@ use crate::{ }; /// The options available when building the arroy database. -pub struct ArroyBuilder<'a, D: Distance, R: Rng + SeedableRng> { +pub struct ArroyBuilder<'a, D: Distance, R: Rng + SeedableRng + Send + Sync> { writer: &'a Writer, rng: &'a mut R, inner: BuildOption<'a>, @@ -114,7 +117,7 @@ impl BuildOption<'_> { } } -impl<'a, D: Distance, R: Rng + SeedableRng> ArroyBuilder<'a, D, R> { +impl<'a, D: Distance, R: Rng + SeedableRng + Send + Sync> ArroyBuilder<'a, D, R> { /// The number of trees to build. If not set arroy will determine the best amount to build for your number of vectors by itself. /// /// # Example @@ -468,11 +471,11 @@ impl Writer { } /// Returns an [`ArroyBuilder`] to configure the available options to build the database. - pub fn builder<'a, R: Rng + SeedableRng>(&'a self, rng: &'a mut R) -> ArroyBuilder<'a, D, R> { + pub fn builder<'a, R: Rng + SeedableRng + Send + Sync>(&'a self, rng: &'a mut R) -> ArroyBuilder<'a, D, R> { ArroyBuilder { writer: self, rng, inner: BuildOption::default() } } - fn build( + fn build( &self, wtxn: &mut RwTxn, rng: &mut R, @@ -512,37 +515,71 @@ impl Writer { // Before taking any references on the DB, remove all the items we must remove. self.delete_items_from_trees(wtxn, options, &mut roots, &to_delete)?; + // From this point on, we're not going to write anything to the DB until the very end. + // Each thread will have its own TmpNodes and we're going to write them all to the DB at the end. + + let leafs = ImmutableLeafs::new(wtxn, self.database, &item_indices, self.index)?; + let immutable_tree_nodes = ImmutableTrees::new(wtxn, self.database, self.index, nb_tree_nodes)?; + let frozen_reader = FrozzenReader { + leafs: &leafs, + trees: &immutable_tree_nodes, + concurrent_node_ids: &concurrent_node_ids, + }; + + let files_tls = Arc::new(ThreadLocal::new()); + // The next method is called from multiple place so we have to update the progress here (options.progress)(WriterProgress { main: MainStep::InsertItemsInCurrentTrees, sub: None }); - let mut large_descendants = self.insert_items_in_current_trees( - wtxn, + let mut descendants = self.insert_items_in_current_trees( rng, options, to_insert, &roots, - nb_tree_nodes, - &concurrent_node_ids, + &frozen_reader, )?; + // Create a new descendant that contains all items for every missing trees let nb_missing_trees = target_n_trees.saturating_sub(roots.len() as u64); for _ in 0..nb_missing_trees { let new_id = concurrent_node_ids.next()?; roots.push(new_id); - large_descendants.insert(new_id); - self.database.put( - wtxn, - &Key::tree(self.index, new_id), - &Node::Descendants(Descendants { descendants: Cow::Borrowed(&item_indices) }), - )?; + descendants.insert(new_id, item_indices.clone()); } - self.incremental_index_large_descendants( - wtxn, - rng, - options, - concurrent_node_ids, - large_descendants, - )?; + let mut new_descendants = IntMap::::default(); + + rayon::scope(|s| { + let frozen_reader = &frozen_reader; + for (descendant_id, mut item_indices) in descendants.into_iter() { + // TODO: Unwrap is NOT safe and must be handled + let old_items = frozen_reader.trees.get(descendant_id).unwrap(); + if let Some(old_items) = old_items { + item_indices |= old_items.descendants().unwrap().descendants.as_ref(); + } + if self.fit_in_descendant(options, item_indices.len()) { + new_descendants.insert(descendant_id, item_indices); + } else { + let rng = StdRng::from_seed(rng.gen()); + let files_tls = files_tls.clone(); + s.spawn( move |s| { + // TODO: find a way to return the error and stop the indexing process + self.incremental_index_large_descendant(rng, options, s, (descendant_id, item_indices), &frozen_reader, files_tls).unwrap(); + }); + } + } + }); + + let files_tls = Arc::into_inner(files_tls).expect("Threads have all finished their works"); + for file in files_tls.into_iter() { + let tmp_nodes = file.into_inner().into_bytes_reader()?; + for (item_id, item_bytes) in tmp_nodes.to_insert() { + self.database.remap_data_type::().put(wtxn, &Key::tree(self.index, item_id), item_bytes)?; + } + } + + for (descendant_id, item_indices) in new_descendants.into_iter() { + self.database.put(wtxn, &Key::tree(self.index, descendant_id), &Node::Descendants(Descendants { descendants: Cow::Borrowed(&item_indices) }))?; + } tracing::debug!("write the metadata..."); (options.progress)(WriterProgress { main: MainStep::WriteTheMetadata, sub: None }); @@ -590,141 +627,100 @@ impl Writer { Ok(()) } - /// Loop over the list of large descendants and split them into sub trees with respect to the available memory. - fn incremental_index_large_descendants( - &self, - wtxn: &mut RwTxn, - rng: &mut R, - options: &BuildOption, - concurrent_node_ids: ConcurrentNodeIds, - mut large_descendants: RoaringBitmap, - ) -> Result<(), Error> { + /// Loop over the items of the specified descendant and explode it into a tree with respect to the available memory. + /// Returns the new descendants that are ready to store in the database. + /// Push more tasks to the scope for all the descendants that are still too large to fit in memory. + /// Write the tree squeleton to its local tmp file. That file must be written to the DB at the end. + fn incremental_index_large_descendant<'scope, R: Rng + SeedableRng + Send + Sync>( + &'scope self, + mut rng: R, + options: &'scope BuildOption, + scope: &Scope<'scope>, + descendant: (ItemId, RoaringBitmap), + frozen_reader: &'scope FrozzenReader, + tmp_nodes: Arc>>>, + ) -> Result<()> { (options.progress)(WriterProgress { main: MainStep::IncrementalIndexLargeDescendants, sub: None, }); + options.cancelled()?; - while let Some(descendant_id) = large_descendants.select(0) { - large_descendants.remove_smallest(1); - options.cancelled()?; - let node = self.database.get(wtxn, &Key::tree(self.index, descendant_id))?.unwrap(); - let Node::Descendants(Descendants { descendants }) = node else { unreachable!() }; - let mut descendants = descendants.into_owned(); + let tmp_node = tmp_nodes.get_or_try(|| { + match self.tmpdir.as_ref() { + Some(path) => TmpNodes::new_in(path).map(RefCell::new), + None => TmpNodes::new().map(RefCell::new), + } + })?; + // Safe to borrow mut here because we're the only thread running with this variable + let mut tmp_node = tmp_node.borrow_mut(); + let mut descendants = IntMap::::default(); + let (descendant_id, mut to_insert) = descendant; - // For each steps of the loop we starts by creating a new sub-tree with as many items as possible - // and then insert all the remaining items that couldn't be selected into this new created tree. - let (leafs, to_insert) = ImmutableLeafs::new( - wtxn, - self.database, - self.index, - &mut descendants, - options.available_memory.unwrap_or(usize::MAX), - )?; - let frozen_reader = FrozzenReader { - leafs: &leafs, - trees: &ImmutableTrees::empty(), - concurrent_node_ids: &concurrent_node_ids, - }; + let available_memory = options.available_memory.unwrap_or(usize::MAX) / current_num_threads(); - let mut tmp_nodes = match self.tmpdir.as_ref() { - Some(path) => TmpNodes::new_in(path)?, - None => TmpNodes::new()?, - }; - let (root_id, nb_new_tree_nodes) = - self.make_tree_in_file(options, &frozen_reader, rng, &to_insert, &mut tmp_nodes)?; - // We cannot update our father so we're going to overwrite the new root node as ourselves. - tmp_nodes.remap(root_id, descendant_id); + // safe to unwrap because we know the descendant is large + let items_for_tree = fit_in_memory::(available_memory, &mut to_insert, self.dimensions).unwrap(); - let tmp_nodes = tmp_nodes.into_bytes_reader()?; - // We never delete anything while building trees - for (item_id, item_bytes) in tmp_nodes.to_insert() { - options.cancelled()?; - let key = Key::tree(self.index, item_id); - self.database.remap_data_type::().put(wtxn, &key, item_bytes)?; - } + let (root_id, _nb_new_tree_nodes) = + self.make_tree_in_file(options, &frozen_reader, &mut rng, &items_for_tree, &mut descendants, Some(descendant_id), &mut tmp_node)?; + assert_eq!(root_id, descendant_id); + + while let Some(to_insert) = fit_in_memory::(available_memory, &mut to_insert, self.dimensions) { + options.cancelled()?; - let descendants_became_too_large = self.insert_items_in_current_trees( - wtxn, - rng, + self.insert_items_in_descendants_from_tmpfile( options, - descendants, - &[descendant_id], - nb_new_tree_nodes, - &concurrent_node_ids, + &frozen_reader, + &mut tmp_node, + &mut rng, + descendant_id, + &to_insert, + &mut descendants, )?; - large_descendants |= descendants_became_too_large; } + for (item_id, item_indices) in descendants.into_iter() { + if self.fit_in_descendant(options, item_indices.len()) { + tmp_node.put(item_id, &Node::Descendants(Descendants { descendants: Cow::Borrowed(&item_indices) }))?; + } else { + let tmp_nodes = tmp_nodes.clone(); + let rng = StdRng::from_seed(rng.gen()); + scope.spawn(move |s| { + // TODO: Find a way to return the error and stop the indexing process + self.incremental_index_large_descendant(rng, options, s, (item_id, item_indices), &frozen_reader, tmp_nodes).unwrap(); + }); + } + } + + Ok(()) } - #[allow(clippy::too_many_arguments)] fn insert_items_in_current_trees( &self, - wtxn: &mut RwTxn, rng: &mut R, options: &BuildOption, mut to_insert: RoaringBitmap, roots: &[ItemId], - nb_tree_nodes: u64, - concurrent_node_ids: &ConcurrentNodeIds, - ) -> Result { + frozen_reader: &FrozzenReader + ) -> Result> { if roots.is_empty() { - return Ok(RoaringBitmap::new()); - } - - // If we have only one roots it means we're splitting a large descendants. - // Otherwise it means we're updating the whole database and will need all the tree nodes. - let immutable_tree_nodes = if roots.len() == 1 { - ImmutableTrees::sub_tree_from_id(wtxn, self.database, self.index, roots[0])? - } else { - ImmutableTrees::new(wtxn, self.database, self.index, nb_tree_nodes)? - }; - let mut descendants_to_update: IntMap = - IntMap::with_hasher(BuildNoHashHasher::default()); - - while !to_insert.is_empty() { - options.cancelled()?; - - let (leafs, to_insert) = ImmutableLeafs::new( - wtxn, - self.database, - self.index, - &mut to_insert, - // We let the indexing process uses 2/3 of the memory for the items and the last third for the tree. - options - .available_memory - .map_or(usize::MAX, |memory| (memory as f64 * 2.0 / 3.0).floor() as usize), - )?; - let frozzen_reader = - FrozzenReader { leafs: &leafs, trees: &immutable_tree_nodes, concurrent_node_ids }; - let tmp_descendant_to_write = - self.insert_items_in_tree(options, rng, roots, &to_insert, &frozzen_reader)?; - for (item_id, descendants) in tmp_descendant_to_write.into_iter() { - descendants_to_update.entry(item_id).or_default().extend(descendants.clone()); - } + return Ok(IntMap::default()); } - let mut large_descendants = RoaringBitmap::new(); + let mut descendants = IntMap::::default(); - for (item_id, descendants) in descendants_to_update.into_iter() { + while let Some(to_insert) = fit_in_memory::(options.available_memory.unwrap_or(usize::MAX), &mut to_insert, self.dimensions) { options.cancelled()?; - let key = Key::tree(self.index, item_id); - let old_node = self.database.get(&wtxn, &key)?.unwrap(); - let Descendants { descendants: original_descendants } = old_node.descendants().unwrap(); - let new_descendants = original_descendants.into_owned() | descendants; - self.database.put( - wtxn, - &key, - &Node::Descendants(Descendants { descendants: Cow::Borrowed(&new_descendants) }), - )?; - if !self.fit_in_descendant(options, new_descendants.len()) { - large_descendants.insert(item_id); + let desc = self.insert_items_in_tree(options, rng, roots, &to_insert, &frozen_reader)?; + for (item_id, desc) in desc { + descendants.entry(item_id).or_default().extend(desc); } } - Ok(large_descendants) + Ok(descendants) } fn reset_and_retrieve_updated_items( @@ -955,7 +951,7 @@ impl Writer { tracing::debug!("started updating tree {root:X}..."); let mut rng = R::seed_from_u64(seed.wrapping_add(*root as u64)); let mut descendants_to_update = IntMap::with_hasher(BuildNoHashHasher::default()); - self.insert_items_in_file( + self.insert_items_in_descendants_from_frozen_reader( opt, frozen_reader, &mut rng, @@ -981,9 +977,9 @@ impl Writer { ) } - /// Find all the descendants that matches the list of items to insert and write them to a file + /// Find all the descendants that matches the list of items to insert and add them to the descendants_to_update map #[allow(clippy::too_many_arguments)] - fn insert_items_in_file( + fn insert_items_in_descendants_from_frozen_reader( &self, opt: &BuildOption, frozen_reader: &FrozzenReader, @@ -1018,7 +1014,7 @@ impl Writer { } } - self.insert_items_in_file( + self.insert_items_in_descendants_from_frozen_reader( opt, frozen_reader, rng, @@ -1026,7 +1022,7 @@ impl Writer { &left_ids, descendants_to_update, )?; - self.insert_items_in_file( + self.insert_items_in_descendants_from_frozen_reader( opt, frozen_reader, rng, @@ -1039,6 +1035,71 @@ impl Writer { Ok(()) } + + /// Find all the descendants that matches the list of items to insert and add them to the descendants_to_update map + #[allow(clippy::too_many_arguments)] + fn insert_items_in_descendants_from_tmpfile( + &self, + opt: &BuildOption, + // We still need this to read the leafs + frozen_reader: &FrozzenReader, + // Must be mutable because we're going to seek and read in it + tmp_nodes: &mut TmpNodes, + rng: &mut R, + current_node: ItemId, + to_insert: &RoaringBitmap, + descendants_to_update: &mut IntMap, + ) -> Result<()> { + opt.cancelled()?; + match tmp_nodes.get(current_node)?.unwrap() { + Node::Leaf(_) => unreachable!(), + Node::Descendants(Descendants { descendants: _ }) => { + descendants_to_update.insert(current_node, to_insert.clone()); + } + Node::SplitPlaneNormal(SplitPlaneNormal { normal, left, right }) => { + // Split the to_insert into two bitmaps on the left and right of this normal + let mut left_ids = RoaringBitmap::new(); + let mut right_ids = RoaringBitmap::new(); + + match normal { + None => { + randomly_split_children(rng, to_insert, &mut left_ids, &mut right_ids); + } + Some(ref normal) => { + for leaf in to_insert { + let node = frozen_reader.leafs.get(leaf)?.unwrap(); + match D::side(normal, &node, rng) { + Side::Left => left_ids.insert(leaf), + Side::Right => right_ids.insert(leaf), + }; + } + } + } + + self.insert_items_in_descendants_from_tmpfile( + opt, + frozen_reader, + tmp_nodes, + rng, + left, + &left_ids, + descendants_to_update, + )?; + self.insert_items_in_descendants_from_tmpfile( + opt, + frozen_reader, + tmp_nodes, + rng, + right, + &right_ids, + descendants_to_update, + )?; + } + } + Ok(()) + } + + /// Creates a tree of nodes from the frozzen items that lives /// in the database and generates descendants, split normal /// and root nodes in files that will be stored in the database later. @@ -1049,13 +1110,15 @@ impl Writer { reader: &FrozzenReader, rng: &mut R, item_indices: &RoaringBitmap, + descendants: &mut IntMap, + next_id: Option, tmp_nodes: &mut TmpNodes, ) -> Result<(ItemId, u64)> { opt.cancelled()?; if self.fit_in_descendant(opt, item_indices.len()) { - let item_id = reader.concurrent_node_ids.next()?; - let item = Node::Descendants(Descendants { descendants: Cow::Borrowed(item_indices) }); - tmp_nodes.put(item_id, &item)?; + let item_id = next_id.map(Ok).unwrap_or_else(|| reader.concurrent_node_ids.next())?; + // Don't write the descendants to the tmp nodes yet because they may become too large later + descendants.insert(item_id, item_indices.clone()); return Ok((item_id, 1)); } @@ -1104,11 +1167,11 @@ impl Writer { ) }; - let (left, l) = self.make_tree_in_file(opt, reader, rng, &children_left, tmp_nodes)?; - let (right, r) = self.make_tree_in_file(opt, reader, rng, &children_right, tmp_nodes)?; + let (left, l) = self.make_tree_in_file(opt, reader, rng, &children_left, descendants, None, tmp_nodes)?; + let (right, r) = self.make_tree_in_file(opt, reader, rng, &children_right, descendants,None, tmp_nodes)?; let normal = SplitPlaneNormal { normal, left, right }; - let new_node_id = reader.concurrent_node_ids.next()?; + let new_node_id = next_id.map(Ok).unwrap_or_else(|| reader.concurrent_node_ids.next())?; tmp_nodes.put(new_node_id, &Node::SplitPlaneNormal(normal))?; Ok((new_node_id, l + r + 1)) @@ -1243,3 +1306,47 @@ pub(crate) fn target_n_trees( } } } + +/// Returns the items from the `to_insert` that fit in memory. +/// If there is no items to insert anymore, returns `None`. +/// If everything fits in memory, returns the `to_insert` bitmap. +/// TODO: We should randomize the items selected. +fn fit_in_memory(memory: usize, to_insert: &mut RoaringBitmap, dimensions: usize) -> Option { + if to_insert.is_empty() { + return None; + } else if to_insert.len() <= dimensions as u64 { + // We need at least dimensions + one extra item to create a split. + // If we return less than that it won't be used. + return Some(std::mem::take(to_insert)); + } + + let page_size = page_size::get(); + let nb_page_allowed = (memory as f64 / page_size as f64).floor() as usize; + let largest_item_size = D::size_of_item(dimensions); + let nb_items_per_page = page_size / largest_item_size; + let nb_page_per_item = (largest_item_size as f64 / page_size as f64).ceil() as usize; + + let nb_items = if nb_items_per_page > 1 { + debug_assert_eq!(nb_page_per_item, 1); + nb_page_allowed * nb_items_per_page + } else if nb_page_per_item > 1 { + debug_assert_eq!(nb_items_per_page, 1); + nb_page_allowed / nb_page_per_item + } else { + nb_page_allowed + }; + + if nb_items as u64 >= to_insert.len() { + return Some(std::mem::take(to_insert)); + } + + let mut items = RoaringBitmap::new(); + + for _ in 0..nb_items { + // Safe to unwrap because we know nb_items is smaller than the number of items in the bitmap + items.push(to_insert.select(0).unwrap()); + to_insert.remove_smallest(1); + } + + Some(items) +} From fe56192917baa44bd6cfc8bc203083e8342956e9 Mon Sep 17 00:00:00 2001 From: Tamo Date: Tue, 10 Jun 2025 22:55:36 +0200 Subject: [PATCH 04/24] randomize the item selection --- src/writer.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/writer.rs b/src/writer.rs index b94fde7..06ba0bf 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -660,13 +660,13 @@ impl Writer { let available_memory = options.available_memory.unwrap_or(usize::MAX) / current_num_threads(); // safe to unwrap because we know the descendant is large - let items_for_tree = fit_in_memory::(available_memory, &mut to_insert, self.dimensions).unwrap(); + let items_for_tree = fit_in_memory::(available_memory, &mut to_insert, self.dimensions, &mut rng).unwrap(); let (root_id, _nb_new_tree_nodes) = self.make_tree_in_file(options, &frozen_reader, &mut rng, &items_for_tree, &mut descendants, Some(descendant_id), &mut tmp_node)?; assert_eq!(root_id, descendant_id); - while let Some(to_insert) = fit_in_memory::(available_memory, &mut to_insert, self.dimensions) { + while let Some(to_insert) = fit_in_memory::(available_memory, &mut to_insert, self.dimensions, &mut rng) { options.cancelled()?; self.insert_items_in_descendants_from_tmpfile( @@ -711,7 +711,7 @@ impl Writer { let mut descendants = IntMap::::default(); - while let Some(to_insert) = fit_in_memory::(options.available_memory.unwrap_or(usize::MAX), &mut to_insert, self.dimensions) { + while let Some(to_insert) = fit_in_memory::(options.available_memory.unwrap_or(usize::MAX), &mut to_insert, self.dimensions, rng) { options.cancelled()?; let desc = self.insert_items_in_tree(options, rng, roots, &to_insert, &frozen_reader)?; @@ -1311,7 +1311,7 @@ pub(crate) fn target_n_trees( /// If there is no items to insert anymore, returns `None`. /// If everything fits in memory, returns the `to_insert` bitmap. /// TODO: We should randomize the items selected. -fn fit_in_memory(memory: usize, to_insert: &mut RoaringBitmap, dimensions: usize) -> Option { +fn fit_in_memory(memory: usize, to_insert: &mut RoaringBitmap, dimensions: usize, rng: &mut R) -> Option { if to_insert.is_empty() { return None; } else if to_insert.len() <= dimensions as u64 { @@ -1343,9 +1343,10 @@ fn fit_in_memory(memory: usize, to_insert: &mut RoaringBitmap, dime let mut items = RoaringBitmap::new(); for _ in 0..nb_items { + let idx = rng.gen_range(0..to_insert.len()); // Safe to unwrap because we know nb_items is smaller than the number of items in the bitmap - items.push(to_insert.select(0).unwrap()); - to_insert.remove_smallest(1); + items.push(to_insert.select(idx as u32).unwrap()); + to_insert.remove_smallest(idx); } Some(items) From ae9c4c291b6dbf563e9563c944cbc341da3d2deb Mon Sep 17 00:00:00 2001 From: Tamo Date: Wed, 11 Jun 2025 09:36:19 +0200 Subject: [PATCH 05/24] get rids of the remap method on the tmp files --- src/parallel.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/parallel.rs b/src/parallel.rs index 55bc309..63d65d8 100644 --- a/src/parallel.rs +++ b/src/parallel.rs @@ -96,7 +96,6 @@ pub struct TmpNodes { ids: Vec, bounds: Vec, deleted: RoaringBitmap, - remap_ids: IntMap, _marker: marker::PhantomData, } @@ -108,7 +107,6 @@ impl<'a, D: Distance> TmpNodes { ids: Vec::new(), bounds: vec![0], deleted: RoaringBitmap::new(), - remap_ids: IntMap::default(), _marker: marker::PhantomData, }) } @@ -120,7 +118,6 @@ impl<'a, D: Distance> TmpNodes { ids: Vec::new(), bounds: vec![0], deleted: RoaringBitmap::new(), - remap_ids: IntMap::default(), _marker: marker::PhantomData, }) } @@ -160,15 +157,6 @@ impl<'a, D: Distance> TmpNodes { Ok(Some(NodeCodec::bytes_decode(&bytes).map_err(heed::Error::Decoding)?.to_owned())) } - /// Remap the item id of an already inserted node to another node. - /// - /// Only applies to the nodes to insert. It won't interact with the to_delete nodes. - pub fn remap(&mut self, current: ItemId, new: ItemId) { - if current != new { - self.remap_ids.insert(current, new); - } - } - /// Delete the tmp_nodes and the node in the database. pub fn remove(&mut self, item: ItemId) { let deleted = self.deleted.insert(item); @@ -187,7 +175,6 @@ impl<'a, D: Distance> TmpNodes { ids: self.ids, bounds: self.bounds, deleted: self.deleted, - remap_ids: self.remap_ids, }) } } @@ -198,7 +185,6 @@ pub struct TmpNodesReader { ids: Vec, bounds: Vec, deleted: RoaringBitmap, - remap_ids: IntMap, } impl TmpNodesReader { @@ -212,10 +198,6 @@ impl TmpNodesReader { .iter() .zip(self.bounds.windows(2)) .filter(|(&id, _)| !self.deleted.contains(id)) - .map(|(id, bounds)| match self.remap_ids.get(id) { - Some(new_id) => (new_id, bounds), - None => (id, bounds), - }) .map(|(id, bounds)| { let [start, end] = [bounds[0], bounds[1]]; (*id, &self.mmap[start..end]) From c11844707b34b7d27fd8b198449d876a9aaf79e0 Mon Sep 17 00:00:00 2001 From: Tamo Date: Wed, 11 Jun 2025 09:59:13 +0200 Subject: [PATCH 06/24] makes the clippy gods happy --- src/node.rs | 2 +- src/parallel.rs | 2 +- src/writer.rs | 260 ++++++++++++++++++++++++------------------------ 3 files changed, 131 insertions(+), 133 deletions(-) diff --git a/src/node.rs b/src/node.rs index c855a62..488f04c 100644 --- a/src/node.rs +++ b/src/node.rs @@ -20,7 +20,7 @@ pub enum Node<'a, D: Distance> { } impl<'a, D: Distance> Node<'a, D> { - pub fn to_owned(self) -> Node<'static, D> { + pub fn into_owned(self) -> Node<'static, D> { match self { Node::Leaf(leaf) => Node::Leaf(leaf.into_owned()), Node::Descendants(descendants) => Node::Descendants(Descendants { diff --git a/src/parallel.rs b/src/parallel.rs index 63d65d8..781d392 100644 --- a/src/parallel.rs +++ b/src/parallel.rs @@ -154,7 +154,7 @@ impl<'a, D: Distance> TmpNodes { }; let bounds = &self.bounds[self.bounds.len() - position - 2..self.bounds.len() - position]; let bytes = self.file.read_all((bounds[0], bounds[1]))?; - Ok(Some(NodeCodec::bytes_decode(&bytes).map_err(heed::Error::Decoding)?.to_owned())) + Ok(Some(NodeCodec::bytes_decode(&bytes).map_err(heed::Error::Decoding)?.into_owned())) } /// Delete the tmp_nodes and the node in the database. diff --git a/src/writer.rs b/src/writer.rs index 06ba0bf..cf1eba4 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -563,7 +563,7 @@ impl Writer { let files_tls = files_tls.clone(); s.spawn( move |s| { // TODO: find a way to return the error and stop the indexing process - self.incremental_index_large_descendant(rng, options, s, (descendant_id, item_indices), &frozen_reader, files_tls).unwrap(); + self.incremental_index_large_descendant(rng, options, s, (descendant_id, item_indices), frozen_reader, files_tls).unwrap(); }); } } @@ -663,15 +663,15 @@ impl Writer { let items_for_tree = fit_in_memory::(available_memory, &mut to_insert, self.dimensions, &mut rng).unwrap(); let (root_id, _nb_new_tree_nodes) = - self.make_tree_in_file(options, &frozen_reader, &mut rng, &items_for_tree, &mut descendants, Some(descendant_id), &mut tmp_node)?; + self.make_tree_in_file(options, frozen_reader, &mut rng, &items_for_tree, &mut descendants, Some(descendant_id), &mut tmp_node)?; assert_eq!(root_id, descendant_id); while let Some(to_insert) = fit_in_memory::(available_memory, &mut to_insert, self.dimensions, &mut rng) { options.cancelled()?; - self.insert_items_in_descendants_from_tmpfile( + insert_items_in_descendants_from_tmpfile( options, - &frozen_reader, + frozen_reader, &mut tmp_node, &mut rng, descendant_id, @@ -688,7 +688,7 @@ impl Writer { let rng = StdRng::from_seed(rng.gen()); scope.spawn(move |s| { // TODO: Find a way to return the error and stop the indexing process - self.incremental_index_large_descendant(rng, options, s, (item_id, item_indices), &frozen_reader, tmp_nodes).unwrap(); + self.incremental_index_large_descendant(rng, options, s, (item_id, item_indices), frozen_reader, tmp_nodes).unwrap(); }); } } @@ -714,7 +714,7 @@ impl Writer { while let Some(to_insert) = fit_in_memory::(options.available_memory.unwrap_or(usize::MAX), &mut to_insert, self.dimensions, rng) { options.cancelled()?; - let desc = self.insert_items_in_tree(options, rng, roots, &to_insert, &frozen_reader)?; + let desc = self.insert_items_in_tree(options, rng, roots, &to_insert, frozen_reader)?; for (item_id, desc) in desc { descendants.entry(item_id).or_default().extend(desc); } @@ -935,7 +935,6 @@ impl Writer { /// Insert items in the specified trees without creating new tree nodes. /// Return the list of nodes modified that must be inserted into the database and /// the roaring bitmap of descendants that became too large in the process. - #[allow(clippy::too_many_arguments)] fn insert_items_in_tree( &self, opt: &BuildOption, @@ -951,7 +950,7 @@ impl Writer { tracing::debug!("started updating tree {root:X}..."); let mut rng = R::seed_from_u64(seed.wrapping_add(*root as u64)); let mut descendants_to_update = IntMap::with_hasher(BuildNoHashHasher::default()); - self.insert_items_in_descendants_from_frozen_reader( + insert_items_in_descendants_from_frozen_reader( opt, frozen_reader, &mut rng, @@ -977,133 +976,11 @@ impl Writer { ) } - /// Find all the descendants that matches the list of items to insert and add them to the descendants_to_update map - #[allow(clippy::too_many_arguments)] - fn insert_items_in_descendants_from_frozen_reader( - &self, - opt: &BuildOption, - frozen_reader: &FrozzenReader, - rng: &mut R, - current_node: ItemId, - to_insert: &RoaringBitmap, - descendants_to_update: &mut IntMap, - ) -> Result<()> { - opt.cancelled()?; - match frozen_reader.trees.get(current_node)?.unwrap() { - Node::Leaf(_) => unreachable!(), - Node::Descendants(Descendants { descendants: _ }) => { - descendants_to_update.insert(current_node, to_insert.clone()); - } - Node::SplitPlaneNormal(SplitPlaneNormal { normal, left, right }) => { - // Split the to_insert into two bitmaps on the left and right of this normal - let mut left_ids = RoaringBitmap::new(); - let mut right_ids = RoaringBitmap::new(); - - match normal { - None => { - randomly_split_children(rng, to_insert, &mut left_ids, &mut right_ids); - } - Some(ref normal) => { - for leaf in to_insert { - let node = frozen_reader.leafs.get(leaf)?.unwrap(); - match D::side(normal, &node, rng) { - Side::Left => left_ids.insert(leaf), - Side::Right => right_ids.insert(leaf), - }; - } - } - } - - self.insert_items_in_descendants_from_frozen_reader( - opt, - frozen_reader, - rng, - left, - &left_ids, - descendants_to_update, - )?; - self.insert_items_in_descendants_from_frozen_reader( - opt, - frozen_reader, - rng, - right, - &right_ids, - descendants_to_update, - )?; - } - } - Ok(()) - } - - - /// Find all the descendants that matches the list of items to insert and add them to the descendants_to_update map - #[allow(clippy::too_many_arguments)] - fn insert_items_in_descendants_from_tmpfile( - &self, - opt: &BuildOption, - // We still need this to read the leafs - frozen_reader: &FrozzenReader, - // Must be mutable because we're going to seek and read in it - tmp_nodes: &mut TmpNodes, - rng: &mut R, - current_node: ItemId, - to_insert: &RoaringBitmap, - descendants_to_update: &mut IntMap, - ) -> Result<()> { - opt.cancelled()?; - match tmp_nodes.get(current_node)?.unwrap() { - Node::Leaf(_) => unreachable!(), - Node::Descendants(Descendants { descendants: _ }) => { - descendants_to_update.insert(current_node, to_insert.clone()); - } - Node::SplitPlaneNormal(SplitPlaneNormal { normal, left, right }) => { - // Split the to_insert into two bitmaps on the left and right of this normal - let mut left_ids = RoaringBitmap::new(); - let mut right_ids = RoaringBitmap::new(); - - match normal { - None => { - randomly_split_children(rng, to_insert, &mut left_ids, &mut right_ids); - } - Some(ref normal) => { - for leaf in to_insert { - let node = frozen_reader.leafs.get(leaf)?.unwrap(); - match D::side(normal, &node, rng) { - Side::Left => left_ids.insert(leaf), - Side::Right => right_ids.insert(leaf), - }; - } - } - } - - self.insert_items_in_descendants_from_tmpfile( - opt, - frozen_reader, - tmp_nodes, - rng, - left, - &left_ids, - descendants_to_update, - )?; - self.insert_items_in_descendants_from_tmpfile( - opt, - frozen_reader, - tmp_nodes, - rng, - right, - &right_ids, - descendants_to_update, - )?; - } - } - Ok(()) - } - - /// Creates a tree of nodes from the frozzen items that lives /// in the database and generates descendants, split normal /// and root nodes in files that will be stored in the database later. /// Return the root node + the total number of tree node generated. + #[allow(clippy::too_many_arguments)] fn make_tree_in_file( &self, opt: &BuildOption, @@ -1307,6 +1184,127 @@ pub(crate) fn target_n_trees( } } + +/// Find all the descendants that matches the list of items to insert and add them to the descendants_to_update map +#[allow(clippy::too_many_arguments)] +fn insert_items_in_descendants_from_frozen_reader( + opt: &BuildOption, + frozen_reader: &FrozzenReader, + rng: &mut R, + current_node: ItemId, + to_insert: &RoaringBitmap, + descendants_to_update: &mut IntMap, +) -> Result<()> { + opt.cancelled()?; + match frozen_reader.trees.get(current_node)?.unwrap() { + Node::Leaf(_) => unreachable!(), + Node::Descendants(Descendants { descendants: _ }) => { + descendants_to_update.insert(current_node, to_insert.clone()); + } + Node::SplitPlaneNormal(SplitPlaneNormal { normal, left, right }) => { + // Split the to_insert into two bitmaps on the left and right of this normal + let mut left_ids = RoaringBitmap::new(); + let mut right_ids = RoaringBitmap::new(); + + match normal { + None => { + randomly_split_children(rng, to_insert, &mut left_ids, &mut right_ids); + } + Some(ref normal) => { + for leaf in to_insert { + let node = frozen_reader.leafs.get(leaf)?.unwrap(); + match D::side(normal, &node, rng) { + Side::Left => left_ids.insert(leaf), + Side::Right => right_ids.insert(leaf), + }; + } + } + } + + insert_items_in_descendants_from_frozen_reader( + opt, + frozen_reader, + rng, + left, + &left_ids, + descendants_to_update, + )?; + insert_items_in_descendants_from_frozen_reader( + opt, + frozen_reader, + rng, + right, + &right_ids, + descendants_to_update, + )?; + } + } + Ok(()) +} + + +/// Find all the descendants that matches the list of items to insert and add them to the descendants_to_update map +#[allow(clippy::too_many_arguments)] +fn insert_items_in_descendants_from_tmpfile( + opt: &BuildOption, + // We still need this to read the leafs + frozen_reader: &FrozzenReader, + // Must be mutable because we're going to seek and read in it + tmp_nodes: &mut TmpNodes, + rng: &mut R, + current_node: ItemId, + to_insert: &RoaringBitmap, + descendants_to_update: &mut IntMap, +) -> Result<()> { + opt.cancelled()?; + match tmp_nodes.get(current_node)?.unwrap() { + Node::Leaf(_) => unreachable!(), + Node::Descendants(Descendants { descendants: _ }) => { + descendants_to_update.insert(current_node, to_insert.clone()); + } + Node::SplitPlaneNormal(SplitPlaneNormal { normal, left, right }) => { + // Split the to_insert into two bitmaps on the left and right of this normal + let mut left_ids = RoaringBitmap::new(); + let mut right_ids = RoaringBitmap::new(); + + match normal { + None => { + randomly_split_children(rng, to_insert, &mut left_ids, &mut right_ids); + } + Some(ref normal) => { + for leaf in to_insert { + let node = frozen_reader.leafs.get(leaf)?.unwrap(); + match D::side(normal, &node, rng) { + Side::Left => left_ids.insert(leaf), + Side::Right => right_ids.insert(leaf), + }; + } + } + } + + insert_items_in_descendants_from_tmpfile( + opt, + frozen_reader, + tmp_nodes, + rng, + left, + &left_ids, + descendants_to_update, + )?; + insert_items_in_descendants_from_tmpfile( + opt, + frozen_reader, + tmp_nodes, + rng, + right, + &right_ids, + descendants_to_update, + )?; + } + } + Ok(()) +} + /// Returns the items from the `to_insert` that fit in memory. /// If there is no items to insert anymore, returns `None`. /// If everything fits in memory, returns the `to_insert` bitmap. From dc14f4b085755bb1568fa15bd04d232a237a9c52 Mon Sep 17 00:00:00 2001 From: Tamo Date: Wed, 11 Jun 2025 10:20:09 +0200 Subject: [PATCH 07/24] fmt --- src/parallel.rs | 15 ++---- src/writer.rs | 122 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 91 insertions(+), 46 deletions(-) diff --git a/src/parallel.rs b/src/parallel.rs index 781d392..72deb04 100644 --- a/src/parallel.rs +++ b/src/parallel.rs @@ -170,12 +170,7 @@ impl<'a, D: Distance> TmpNodes { let mmap = unsafe { Mmap::map(&file)? }; #[cfg(unix)] mmap.advise(memmap2::Advice::Sequential)?; - Ok(TmpNodesReader { - mmap, - ids: self.ids, - bounds: self.bounds, - deleted: self.deleted, - }) + Ok(TmpNodesReader { mmap, ids: self.ids, bounds: self.bounds, deleted: self.deleted }) } } @@ -276,10 +271,8 @@ impl<'t, D: Distance> ImmutableLeafs<'t, D> { items: &RoaringBitmap, index: u16, ) -> heed::Result { - let mut leafs = IntMap::with_capacity_and_hasher( - items.len() as usize, - BuildNoHashHasher::default(), - ); + let mut leafs = + IntMap::with_capacity_and_hasher(items.len() as usize, BuildNoHashHasher::default()); let mut constant_length = None; for item_id in items { @@ -294,7 +287,7 @@ impl<'t, D: Distance> ImmutableLeafs<'t, D> { Ok(ImmutableLeafs { leafs, constant_length, _marker: marker::PhantomData }) } - /// Creates the structure by fetching all the leaf pointers + /// Creates the structure by fetching all the leaf pointers /// and keeping the transaction making the pointers valid. /// Do not take more items than memory allows. /// Remove from the list of candidates all the items that were selected and return them. diff --git a/src/writer.rs b/src/writer.rs index cf1eba4..9d1c257 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -471,7 +471,10 @@ impl Writer { } /// Returns an [`ArroyBuilder`] to configure the available options to build the database. - pub fn builder<'a, R: Rng + SeedableRng + Send + Sync>(&'a self, rng: &'a mut R) -> ArroyBuilder<'a, D, R> { + pub fn builder<'a, R: Rng + SeedableRng + Send + Sync>( + &'a self, + rng: &'a mut R, + ) -> ArroyBuilder<'a, D, R> { ArroyBuilder { writer: self, rng, inner: BuildOption::default() } } @@ -519,7 +522,8 @@ impl Writer { // Each thread will have its own TmpNodes and we're going to write them all to the DB at the end. let leafs = ImmutableLeafs::new(wtxn, self.database, &item_indices, self.index)?; - let immutable_tree_nodes = ImmutableTrees::new(wtxn, self.database, self.index, nb_tree_nodes)?; + let immutable_tree_nodes = + ImmutableTrees::new(wtxn, self.database, self.index, nb_tree_nodes)?; let frozen_reader = FrozzenReader { leafs: &leafs, trees: &immutable_tree_nodes, @@ -530,13 +534,8 @@ impl Writer { // The next method is called from multiple place so we have to update the progress here (options.progress)(WriterProgress { main: MainStep::InsertItemsInCurrentTrees, sub: None }); - let mut descendants = self.insert_items_in_current_trees( - rng, - options, - to_insert, - &roots, - &frozen_reader, - )?; + let mut descendants = + self.insert_items_in_current_trees(rng, options, to_insert, &roots, &frozen_reader)?; // Create a new descendant that contains all items for every missing trees let nb_missing_trees = target_n_trees.saturating_sub(roots.len() as u64); @@ -561,9 +560,17 @@ impl Writer { } else { let rng = StdRng::from_seed(rng.gen()); let files_tls = files_tls.clone(); - s.spawn( move |s| { + s.spawn(move |s| { // TODO: find a way to return the error and stop the indexing process - self.incremental_index_large_descendant(rng, options, s, (descendant_id, item_indices), frozen_reader, files_tls).unwrap(); + self.incremental_index_large_descendant( + rng, + options, + s, + (descendant_id, item_indices), + frozen_reader, + files_tls, + ) + .unwrap(); }); } } @@ -573,12 +580,20 @@ impl Writer { for file in files_tls.into_iter() { let tmp_nodes = file.into_inner().into_bytes_reader()?; for (item_id, item_bytes) in tmp_nodes.to_insert() { - self.database.remap_data_type::().put(wtxn, &Key::tree(self.index, item_id), item_bytes)?; + self.database.remap_data_type::().put( + wtxn, + &Key::tree(self.index, item_id), + item_bytes, + )?; } } for (descendant_id, item_indices) in new_descendants.into_iter() { - self.database.put(wtxn, &Key::tree(self.index, descendant_id), &Node::Descendants(Descendants { descendants: Cow::Borrowed(&item_indices) }))?; + self.database.put( + wtxn, + &Key::tree(self.index, descendant_id), + &Node::Descendants(Descendants { descendants: Cow::Borrowed(&item_indices) }), + )?; } tracing::debug!("write the metadata..."); @@ -646,27 +661,37 @@ impl Writer { }); options.cancelled()?; - let tmp_node = tmp_nodes.get_or_try(|| { - match self.tmpdir.as_ref() { - Some(path) => TmpNodes::new_in(path).map(RefCell::new), - None => TmpNodes::new().map(RefCell::new), - } + let tmp_node = tmp_nodes.get_or_try(|| match self.tmpdir.as_ref() { + Some(path) => TmpNodes::new_in(path).map(RefCell::new), + None => TmpNodes::new().map(RefCell::new), })?; // Safe to borrow mut here because we're the only thread running with this variable let mut tmp_node = tmp_node.borrow_mut(); let mut descendants = IntMap::::default(); let (descendant_id, mut to_insert) = descendant; - let available_memory = options.available_memory.unwrap_or(usize::MAX) / current_num_threads(); + let available_memory = + options.available_memory.unwrap_or(usize::MAX) / current_num_threads(); // safe to unwrap because we know the descendant is large - let items_for_tree = fit_in_memory::(available_memory, &mut to_insert, self.dimensions, &mut rng).unwrap(); + let items_for_tree = + fit_in_memory::(available_memory, &mut to_insert, self.dimensions, &mut rng) + .unwrap(); - let (root_id, _nb_new_tree_nodes) = - self.make_tree_in_file(options, frozen_reader, &mut rng, &items_for_tree, &mut descendants, Some(descendant_id), &mut tmp_node)?; + let (root_id, _nb_new_tree_nodes) = self.make_tree_in_file( + options, + frozen_reader, + &mut rng, + &items_for_tree, + &mut descendants, + Some(descendant_id), + &mut tmp_node, + )?; assert_eq!(root_id, descendant_id); - - while let Some(to_insert) = fit_in_memory::(available_memory, &mut to_insert, self.dimensions, &mut rng) { + + while let Some(to_insert) = + fit_in_memory::(available_memory, &mut to_insert, self.dimensions, &mut rng) + { options.cancelled()?; insert_items_in_descendants_from_tmpfile( @@ -682,18 +707,28 @@ impl Writer { for (item_id, item_indices) in descendants.into_iter() { if self.fit_in_descendant(options, item_indices.len()) { - tmp_node.put(item_id, &Node::Descendants(Descendants { descendants: Cow::Borrowed(&item_indices) }))?; + tmp_node.put( + item_id, + &Node::Descendants(Descendants { descendants: Cow::Borrowed(&item_indices) }), + )?; } else { let tmp_nodes = tmp_nodes.clone(); let rng = StdRng::from_seed(rng.gen()); scope.spawn(move |s| { // TODO: Find a way to return the error and stop the indexing process - self.incremental_index_large_descendant(rng, options, s, (item_id, item_indices), frozen_reader, tmp_nodes).unwrap(); + self.incremental_index_large_descendant( + rng, + options, + s, + (item_id, item_indices), + frozen_reader, + tmp_nodes, + ) + .unwrap(); }); } } - Ok(()) } @@ -703,7 +738,7 @@ impl Writer { options: &BuildOption, mut to_insert: RoaringBitmap, roots: &[ItemId], - frozen_reader: &FrozzenReader + frozen_reader: &FrozzenReader, ) -> Result> { if roots.is_empty() { return Ok(IntMap::default()); @@ -711,7 +746,12 @@ impl Writer { let mut descendants = IntMap::::default(); - while let Some(to_insert) = fit_in_memory::(options.available_memory.unwrap_or(usize::MAX), &mut to_insert, self.dimensions, rng) { + while let Some(to_insert) = fit_in_memory::( + options.available_memory.unwrap_or(usize::MAX), + &mut to_insert, + self.dimensions, + rng, + ) { options.cancelled()?; let desc = self.insert_items_in_tree(options, rng, roots, &to_insert, frozen_reader)?; @@ -1044,8 +1084,17 @@ impl Writer { ) }; - let (left, l) = self.make_tree_in_file(opt, reader, rng, &children_left, descendants, None, tmp_nodes)?; - let (right, r) = self.make_tree_in_file(opt, reader, rng, &children_right, descendants,None, tmp_nodes)?; + let (left, l) = + self.make_tree_in_file(opt, reader, rng, &children_left, descendants, None, tmp_nodes)?; + let (right, r) = self.make_tree_in_file( + opt, + reader, + rng, + &children_right, + descendants, + None, + tmp_nodes, + )?; let normal = SplitPlaneNormal { normal, left, right }; let new_node_id = next_id.map(Ok).unwrap_or_else(|| reader.concurrent_node_ids.next())?; @@ -1184,7 +1233,6 @@ pub(crate) fn target_n_trees( } } - /// Find all the descendants that matches the list of items to insert and add them to the descendants_to_update map #[allow(clippy::too_many_arguments)] fn insert_items_in_descendants_from_frozen_reader( @@ -1242,7 +1290,6 @@ fn insert_items_in_descendants_from_frozen_reader( Ok(()) } - /// Find all the descendants that matches the list of items to insert and add them to the descendants_to_update map #[allow(clippy::too_many_arguments)] fn insert_items_in_descendants_from_tmpfile( @@ -1309,7 +1356,12 @@ fn insert_items_in_descendants_from_tmpfile( /// If there is no items to insert anymore, returns `None`. /// If everything fits in memory, returns the `to_insert` bitmap. /// TODO: We should randomize the items selected. -fn fit_in_memory(memory: usize, to_insert: &mut RoaringBitmap, dimensions: usize, rng: &mut R) -> Option { +fn fit_in_memory( + memory: usize, + to_insert: &mut RoaringBitmap, + dimensions: usize, + rng: &mut R, +) -> Option { if to_insert.is_empty() { return None; } else if to_insert.len() <= dimensions as u64 { @@ -1326,7 +1378,7 @@ fn fit_in_memory(memory: usize, to_insert: &mut RoaringBitm let nb_items = if nb_items_per_page > 1 { debug_assert_eq!(nb_page_per_item, 1); - nb_page_allowed * nb_items_per_page + nb_page_allowed * nb_items_per_page } else if nb_page_per_item > 1 { debug_assert_eq!(nb_items_per_page, 1); nb_page_allowed / nb_page_per_item From 9c702222265fbde20e478c6bc5ade4653ed6a24c Mon Sep 17 00:00:00 2001 From: Tamo Date: Thu, 12 Jun 2025 11:55:35 +0200 Subject: [PATCH 08/24] Make the deletion of items faster --- src/tests/writer.rs | 26 +++++------ src/writer.rs | 103 ++++++++++++++++++++++++++------------------ 2 files changed, 74 insertions(+), 55 deletions(-) diff --git a/src/tests/writer.rs b/src/tests/writer.rs index e8bd8f7..d0042a0 100644 --- a/src/tests/writer.rs +++ b/src/tests/writer.rs @@ -1072,6 +1072,7 @@ fn create_root_split_node_with_empty_child() { Item 5: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [5.0000, 0.0000] }) "#); + println!("HEEEEEERE"); let mut wtxn = handle.env.write_txn().unwrap(); let writer = Writer::new(handle.database, 0, 2); @@ -1155,8 +1156,7 @@ fn reuse_node_id() { let mut wtxn = handle.env.write_txn().unwrap(); let writer = Writer::new(handle.database, 0, 2); - // if we delete the 3 and 4 it should free the tree node 2 - writer.del_item(&mut wtxn, 3).unwrap(); + // if we delete 4 it should free the tree node 3 and 5 writer.del_item(&mut wtxn, 4).unwrap(); writer.builder(&mut rng).n_trees(1).build(&mut wtxn).unwrap(); wtxn.commit().unwrap(); @@ -1164,24 +1164,24 @@ fn reuse_node_id() { insta::assert_snapshot!(handle, @r#" ================== Dumping index 0 - Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 5]>, roots: [0], distance: "euclidean" } + Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 5]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 6, normal: [1.0000, 0.0000] }) Tree 1: Descendants(Descendants { descendants: [0] }) Tree 2: Descendants(Descendants { descendants: [1, 5] }) - Tree 5: Descendants(Descendants { descendants: [2] }) - Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 5, normal: "none" }) + Tree 4: Descendants(Descendants { descendants: [2, 3] }) + Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 4, normal: "none" }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [2.0000, 0.0000] }) + Item 3: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [3.0000, 0.0000] }) Item 5: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [5.0000, 0.0000] }) "#); let mut wtxn = handle.env.write_txn().unwrap(); let writer = Writer::new(handle.database, 0, 2); - // if we re-insert both nodes, the id 2 should be re-used - writer.add_item(&mut wtxn, 3, &[3., 0.]).unwrap(); + // if we re-insert both nodes, the ids 3 and 5 should be re-used writer.add_item(&mut wtxn, 4, &[4., 0.]).unwrap(); writer.builder(&mut rng).n_trees(1).build(&mut wtxn).unwrap(); wtxn.commit().unwrap(); @@ -1195,9 +1195,9 @@ fn reuse_node_id() { Tree 1: Descendants(Descendants { descendants: [0] }) Tree 2: Descendants(Descendants { descendants: [1, 5] }) Tree 3: Descendants(Descendants { descendants: [3] }) - Tree 4: Descendants(Descendants { descendants: [2, 4] }) - Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) - Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 5, normal: "none" }) + Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 5, normal: "none" }) + Tree 5: Descendants(Descendants { descendants: [2, 4] }) + Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 4, normal: "none" }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: 0.0 }, vector: [2.0000, 0.0000] }) @@ -1222,9 +1222,9 @@ fn reuse_node_id() { Tree 1: Descendants(Descendants { descendants: [0] }) Tree 2: Descendants(Descendants { descendants: [1, 5] }) Tree 3: Descendants(Descendants { descendants: [3] }) - Tree 4: Descendants(Descendants { descendants: [2, 4] }) - Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: "none" }) - Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 5, normal: "none" }) + Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 5, normal: "none" }) + Tree 5: Descendants(Descendants { descendants: [2, 4] }) + Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 4, normal: "none" }) Tree 7: SplitPlaneNormal(SplitPlaneNormal { left: 14, right: 15, normal: [-1.0000, 0.0000] }) Tree 8: Descendants(Descendants { descendants: [1] }) Tree 9: Descendants(Descendants { descendants: [5] }) diff --git a/src/writer.rs b/src/writer.rs index 9d1c257..25e5f4f 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -892,6 +892,8 @@ impl Writer { /// Remove items in O(n). We must explore the whole list of items. /// That could be reduced to O(log(n)) if we had a `RoTxn` of the previous state of the database. + /// Return the new node id and the list of all the items contained in this branch. + /// If there is too many items to create a single descendant, we return `None`. fn delete_items_in_file( &self, options: &BuildOption, @@ -899,7 +901,7 @@ impl Writer { current_node: ItemId, tmp_nodes: &mut TmpNodes, to_delete: &RoaringBitmap, - ) -> Result<(ItemId, RoaringBitmap)> { + ) -> Result<(ItemId, Option)> { options.cancelled()?; match self.database.get(rtxn, &Key::tree(self.index, current_node))?.unwrap() { Node::Leaf(_) => unreachable!(), @@ -917,7 +919,7 @@ impl Writer { }), )?; } - Ok((current_node, new_descendants)) + Ok((current_node, Some(new_descendants))) } Node::SplitPlaneNormal(SplitPlaneNormal { normal, left, right }) => { let (new_left, left_items) = @@ -926,47 +928,64 @@ impl Writer { let (new_right, right_items) = self.delete_items_in_file(options, rtxn, right, tmp_nodes, to_delete)?; - let total_items = &left_items | &right_items; - - if self.fit_in_descendant(options, total_items.len()) { - // Since we're shrinking we KNOW that new_left and new_right are descendants - // thus we can delete them directly knowing there is no sub-tree to look at. - tmp_nodes.remove(new_left); - tmp_nodes.remove(new_right); - - tmp_nodes.put( - current_node, - &Node::Descendants(Descendants { - descendants: Cow::Owned(total_items.clone()), - }), - )?; - - // we should merge both branch and update ourselves to be a single descendant node - Ok((current_node, total_items)) - - // If we don't have any items in either the left or right we can delete ourselves and point directly to our child - } else if left_items.is_empty() { - tmp_nodes.remove(new_left); - tmp_nodes.remove(current_node); - Ok((new_right, total_items)) - } else if right_items.is_empty() { - tmp_nodes.remove(new_right); - tmp_nodes.remove(current_node); - Ok((new_left, total_items)) - } else { - // if either the left or the right changed we must update ourselves inplace - if new_left != left || new_right != right { - tmp_nodes.put( - current_node, - &Node::SplitPlaneNormal(SplitPlaneNormal { - normal, - left: new_left, - right: new_right, - }), - )?; + match (left_items, right_items) { + (Some(left_items), right_items) if left_items.is_empty() => { + println!("left_items is empty"); + tmp_nodes.remove(new_left); + tmp_nodes.remove(current_node); + Ok((new_right, right_items)) + } + (left_items, Some(right_items)) if right_items.is_empty() => { + println!("right_items is empty"); + tmp_nodes.remove(new_right); + tmp_nodes.remove(current_node); + Ok((new_left, left_items)) + } + (Some(left_items), Some(right_items)) => { + let total_items = left_items.len() + right_items.len(); + if self.fit_in_descendant(options, total_items as u64) { + let total_items = left_items | right_items; + // Since we're shrinking we KNOW that new_left and new_right are descendants + // thus we can delete them directly knowing there is no sub-tree to look at. + tmp_nodes.remove(new_left); + tmp_nodes.remove(new_right); + + tmp_nodes.put( + current_node, + &Node::Descendants(Descendants { + descendants: Cow::Borrowed(&total_items), + }), + )?; + + // we should merge both branch and update ourselves to be a single descendant node + Ok((current_node, Some(total_items))) + } else { + if new_left != left || new_right != right { + tmp_nodes.put( + current_node, + &Node::SplitPlaneNormal(SplitPlaneNormal { + normal, + left: new_left, + right: new_right, + }), + )?; + } + Ok((current_node, None)) + } + } + (None, Some(_)) | (Some(_), None) | (None, None) => { + if new_left != left || new_right != right { + tmp_nodes.put( + current_node, + &Node::SplitPlaneNormal(SplitPlaneNormal { + normal, + left: new_left, + right: new_right, + }), + )?; + } + Ok((current_node, None)) } - - Ok((current_node, total_items)) } } } From ae21f605dc1277cc5e48ad577ed18a58a39fd451 Mon Sep 17 00:00:00 2001 From: Tamo Date: Thu, 12 Jun 2025 19:38:21 +0200 Subject: [PATCH 09/24] fmt --- src/node.rs | 5 ++++- src/tests/tmp_nodes.rs | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/node.rs b/src/node.rs index a62d012..5d5ab37 100644 --- a/src/node.rs +++ b/src/node.rs @@ -168,7 +168,10 @@ impl SplitPlaneNormal<'_, D> { SplitPlaneNormal { left: self.left, right: self.right, - normal: self.normal.map(|normal| Leaf { header: normal.header, vector: Cow::Owned(normal.vector.into_owned()) }), + normal: self.normal.map(|normal| Leaf { + header: normal.header, + vector: Cow::Owned(normal.vector.into_owned()), + }), } } } diff --git a/src/tests/tmp_nodes.rs b/src/tests/tmp_nodes.rs index 5bfb5e4..98460fd 100644 --- a/src/tests/tmp_nodes.rs +++ b/src/tests/tmp_nodes.rs @@ -48,8 +48,11 @@ fn test_put_and_get_tmp_nodes() { for i in 11..20 { let normal = if i % 2 == 0 { Some(UnalignedVector::from_vec(vec![i as f32])) } else { None }; - let node = - Node::SplitPlaneNormal(SplitPlaneNormal { left: i * 2, right: i * 2 + 1, normal: normal.map(|v| Leaf { header: NodeHeaderCosine { norm: 0. }, vector: v }) }); + let node = Node::SplitPlaneNormal(SplitPlaneNormal { + left: i * 2, + right: i * 2 + 1, + normal: normal.map(|v| Leaf { header: NodeHeaderCosine { norm: 0. }, vector: v }), + }); tmp_nodes.put(i, &node).unwrap(); } From 9c29c04cd462570e06feeaf14a015fafe269995d Mon Sep 17 00:00:00 2001 From: Tamo Date: Thu, 12 Jun 2025 19:39:56 +0200 Subject: [PATCH 10/24] make clippy happy --- src/writer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/writer.rs b/src/writer.rs index 50b929b..a6b0d9b 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -943,7 +943,7 @@ impl Writer { } (Some(left_items), Some(right_items)) => { let total_items = left_items.len() + right_items.len(); - if self.fit_in_descendant(options, total_items as u64) { + if self.fit_in_descendant(options, total_items) { let total_items = left_items | right_items; // Since we're shrinking we KNOW that new_left and new_right are descendants // thus we can delete them directly knowing there is no sub-tree to look at. From a16fbdd4623115222225d3adbc91f80bc542978c Mon Sep 17 00:00:00 2001 From: Tamo Date: Mon, 16 Jun 2025 16:12:18 +0200 Subject: [PATCH 11/24] share the code between the writer and the incremental indexing. That changed the rng and some snapshots --- ...ite_and_update_lot_of_random_points-2.snap | 280 +++++++++--------- ...write_and_update_lot_of_random_points.snap | 190 ++++++------ src/tests/writer.rs | 236 +++++++-------- src/writer.rs | 78 ++--- 4 files changed, 396 insertions(+), 388 deletions(-) diff --git a/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points-2.snap b/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points-2.snap index 6d73a92..f569e84 100644 --- a/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points-2.snap +++ b/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points-2.snap @@ -6,191 +6,195 @@ expression: handle Dumping index 0 Root: Metadata { dimensions: 30, items: RoaringBitmap<100 values between 0 and 99>, roots: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } -Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 92, right: 97, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3716" }, vector: [0.1332, -0.0086, -0.0332, 0.3903, -0.1149, 0.0165, 0.0177, -0.2272, -0.0616, -0.0471, "other ..."] } }) -Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 82, right: 87, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3513" }, vector: [-0.1907, 0.0249, 0.0882, 0.0445, 0.0329, 0.2224, -0.0366, -0.3159, -0.1131, 0.1267, "other ..."] } }) -Tree 2: SplitPlaneNormal(SplitPlaneNormal { left: 72, right: 79, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.4519" }, vector: [0.1173, 0.3077, 0.0145, 0.0027, -0.3801, 0.1215, -0.1959, -0.1847, -0.1231, 0.0874, "other ..."] } }) -Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 62, right: 69, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.5850" }, vector: [0.0380, 0.1603, -0.3896, -0.1186, 0.0911, -0.0967, -0.0213, 0.2811, -0.3599, -0.4255, "other ..."] } }) -Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 56, right: 59, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0456" }, vector: [-0.1512, 0.1699, 0.2254, -0.2646, -0.2503, 0.2765, -0.1126, -0.0710, -0.0636, -0.0934, "other ..."] } }) -Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 44, right: 51, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.6517" }, vector: [-0.1426, 0.1041, -0.0253, 0.2489, 0.0095, -0.0057, 0.0741, -0.0359, -0.1958, 0.2323, "other ..."] } }) -Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 38, right: 41, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.2643" }, vector: [0.1950, -0.3941, -0.2712, 0.0233, 0.1903, 0.4587, -0.1344, -0.0574, -0.0227, -0.2019, "other ..."] } }) -Tree 7: SplitPlaneNormal(SplitPlaneNormal { left: 30, right: 33, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0533" }, vector: [0.0260, 0.0441, -0.0001, 0.1366, 0.2223, 0.0095, 0.0044, 0.2319, -0.2957, -0.0180, "other ..."] } }) -Tree 8: SplitPlaneNormal(SplitPlaneNormal { left: 22, right: 25, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3110" }, vector: [-0.0130, 0.0421, 0.0374, -0.3224, -0.2745, 0.0954, 0.1471, -0.0139, 0.1443, 0.3814, "other ..."] } }) -Tree 9: SplitPlaneNormal(SplitPlaneNormal { left: 14, right: 17, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0740" }, vector: [-0.1374, 0.0838, -0.0510, 0.1656, -0.1541, -0.1150, -0.2054, -0.4952, -0.3053, -0.0348, "other ..."] } }) -Tree 10: Descendants(Descendants { descendants: [0, 2, 21, 34, 40, 41, 43, 48, 50, 54, 56, 59, 67, 73, 81, 83] }) -Tree 13: SplitPlaneNormal(SplitPlaneNormal { left: 126, right: 129, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0875" }, vector: [-0.3763, -0.1106, 0.2365, 0.2438, -0.1057, 0.1098, 0.1099, -0.0047, -0.0750, -0.0282, "other ..."] } }) -Tree 14: SplitPlaneNormal(SplitPlaneNormal { left: 10, right: 13, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.2300" }, vector: [-0.0720, -0.0814, 0.0454, -0.0944, -0.0123, -0.2516, 0.1854, 0.3585, 0.1772, 0.3414, "other ..."] } }) -Tree 17: Descendants(Descendants { descendants: [1, 5, 6, 13, 19, 20, 24, 25, 27, 30, 31, 33, 36, 42, 45, 46, 49, 51, 57, 58, 61, 63, 66, 72, 82, 84, 87, 90, 91, 93] }) -Tree 22: SplitPlaneNormal(SplitPlaneNormal { left: 112, right: 113, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.2418" }, vector: [0.2765, 0.1069, 0.2099, -0.0624, 0.0167, 0.0517, -0.1851, -0.0459, -0.0704, 0.0095, "other ..."] } }) -Tree 25: SplitPlaneNormal(SplitPlaneNormal { left: 110, right: 111, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.2050" }, vector: [-0.1824, 0.2644, 0.0247, -0.1615, 0.1712, -0.0965, 0.0843, 0.1959, -0.1788, -0.0065, "other ..."] } }) -Tree 30: SplitPlaneNormal(SplitPlaneNormal { left: 100, right: 101, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.8616" }, vector: [0.1260, 0.0026, -0.1321, 0.2770, 0.0904, -0.0650, 0.1187, 0.2023, 0.1102, -0.0878, "other ..."] } }) -Tree 33: SplitPlaneNormal(SplitPlaneNormal { left: 140, right: 141, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.2767" }, vector: [-0.2012, 0.0192, -0.3268, -0.2095, 0.1420, 0.1479, 0.3250, 0.1448, 0.0366, 0.0747, "other ..."] } }) -Tree 38: SplitPlaneNormal(SplitPlaneNormal { left: 138, right: 139, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.5352" }, vector: [0.2050, 0.1943, 0.0858, -0.2534, -0.2716, 0.1622, -0.3585, 0.0532, -0.0648, -0.1576, "other ..."] } }) -Tree 41: SplitPlaneNormal(SplitPlaneNormal { left: 132, right: 135, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.2382" }, vector: [0.1089, -0.1728, -0.0823, 0.0013, -0.1088, -0.0610, 0.4129, -0.0623, -0.1278, 0.1866, "other ..."] } }) -Tree 44: Descendants(Descendants { descendants: [0, 2, 5, 14, 15, 18, 19, 22, 23, 27, 34, 37, 44, 45, 48, 59, 67, 71, 73, 74, 75, 77, 82, 87, 91, 92, 96] }) -Tree 45: Descendants(Descendants { descendants: [6, 8, 13, 25, 39, 50, 52, 80, 85, 88, 93] }) -Tree 50: SplitPlaneNormal(SplitPlaneNormal { left: 120, right: 121, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.5256" }, vector: [-0.2480, -0.2556, -0.0299, -0.1149, -0.3880, 0.0975, 0.1812, 0.0228, 0.0743, -0.0461, "other ..."] } }) -Tree 51: SplitPlaneNormal(SplitPlaneNormal { left: 45, right: 50, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.6595" }, vector: [-0.0635, -0.2061, -0.0851, 0.1272, 0.0083, -0.2721, 0.1119, 0.2789, 0.2137, 0.1339, "other ..."] } }) -Tree 54: SplitPlaneNormal(SplitPlaneNormal { left: 116, right: 117, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.6160" }, vector: [-0.0149, -0.2113, 0.3446, -0.0674, 0.1514, 0.0063, -0.2041, -0.0915, -0.0053, 0.0564, "other ..."] } }) -Tree 55: Descendants(Descendants { descendants: [3, 17, 19, 21, 23, 40, 41, 44, 54, 64, 71, 79, 81] }) -Tree 56: SplitPlaneNormal(SplitPlaneNormal { left: 54, right: 55, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3720" }, vector: [0.0401, 0.3800, 0.2200, 0.1918, -0.1184, -0.1624, -0.3477, 0.0335, 0.3667, -0.0673, "other ..."] } }) -Tree 59: SplitPlaneNormal(SplitPlaneNormal { left: 106, right: 107, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9848" }, vector: [-0.1892, -0.0230, -0.0544, 0.1613, -0.1112, -0.0481, 0.2321, 0.3393, 0.1349, 0.1389, "other ..."] } }) -Tree 62: SplitPlaneNormal(SplitPlaneNormal { left: 102, right: 103, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3370" }, vector: [0.2102, -0.0191, -0.1754, -0.3604, -0.2472, -0.1116, 0.2185, 0.0573, -0.1071, 0.0613, "other ..."] } }) -Tree 65: SplitPlaneNormal(SplitPlaneNormal { left: 142, right: 143, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0270" }, vector: [0.0959, 0.0063, -0.0087, -0.3784, -0.3572, -0.0111, 0.0194, 0.0951, 0.1028, -0.1269, "other ..."] } }) -Tree 68: Descendants(Descendants { descendants: [0, 1, 13, 14, 19, 23, 34, 35, 36, 38, 41, 43, 47, 53, 54, 58, 61, 64, 69, 71, 73, 75, 76, 80, 83, 87, 98, 99] }) -Tree 69: SplitPlaneNormal(SplitPlaneNormal { left: 65, right: 68, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3590" }, vector: [-0.0595, -0.0724, -0.5327, 0.1397, 0.1090, -0.0954, 0.0156, -0.2676, 0.1233, 0.2413, "other ..."] } }) -Tree 72: SplitPlaneNormal(SplitPlaneNormal { left: 136, right: 137, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3329" }, vector: [-0.1187, -0.1402, 0.1600, -0.0999, 0.1095, 0.1909, 0.0062, 0.0047, -0.4649, -0.0603, "other ..."] } }) -Tree 73: Descendants(Descendants { descendants: [5, 7, 8, 12, 14, 15, 17, 23, 24, 30, 32, 36, 42, 43, 48, 52, 53, 55, 58, 59, 70, 77, 87, 89, 90, 93, 96, 99] }) -Tree 78: SplitPlaneNormal(SplitPlaneNormal { left: 130, right: 131, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3299" }, vector: [0.0617, 0.2725, -0.1684, -0.2569, -0.0755, -0.0076, 0.3176, 0.1323, 0.2489, 0.0931, "other ..."] } }) -Tree 79: SplitPlaneNormal(SplitPlaneNormal { left: 73, right: 78, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0254" }, vector: [0.1396, 0.0343, -0.3978, 0.3344, 0.0795, 0.2614, 0.0287, -0.2709, 0.1147, -0.1712, "other ..."] } }) -Tree 82: SplitPlaneNormal(SplitPlaneNormal { left: 122, right: 125, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.5010" }, vector: [0.0606, 0.0605, -0.1728, 0.0474, 0.1211, 0.1019, 0.0550, 0.0040, -0.0996, 0.1212, "other ..."] } }) -Tree 87: SplitPlaneNormal(SplitPlaneNormal { left: 114, right: 115, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.1298" }, vector: [0.0448, -0.0452, 0.2191, 0.0952, 0.2910, -0.2318, -0.1062, -0.2497, -0.1915, 0.0911, "other ..."] } }) -Tree 92: SplitPlaneNormal(SplitPlaneNormal { left: 104, right: 105, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.6578" }, vector: [-0.2181, 0.0150, 0.3510, -0.1055, 0.2094, 0.1523, -0.1721, 0.0816, -0.4673, 0.0634, "other ..."] } }) -Tree 97: SplitPlaneNormal(SplitPlaneNormal { left: 144, right: 145, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3155" }, vector: [0.1066, 0.0713, 0.0798, 0.0481, -0.1497, 0.1283, -0.0884, 0.1558, -0.1191, -0.1191, "other ..."] } }) -Tree 98: Descendants(Descendants { descendants: [0, 14, 17, 22, 25, 34, 35, 38, 40, 42, 49, 55, 56, 58, 71, 75, 76, 90, 94, 98] }) -Tree 99: Descendants(Descendants { descendants: [5, 9, 15, 23, 48, 59, 60, 61, 64, 70, 77, 81, 83, 87, 91, 99] }) -Tree 100: SplitPlaneNormal(SplitPlaneNormal { left: 98, right: 99, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.1982" }, vector: [0.2175, 0.2650, 0.1519, -0.2454, 0.0141, 0.0907, -0.2576, 0.1270, -0.2462, -0.0094, "other ..."] } }) -Tree 101: Descendants(Descendants { descendants: [4, 6, 11, 16, 19, 26, 28, 30, 31, 32, 33, 36, 41, 43, 44, 46, 53, 54, 62, 69, 79, 85, 86] }) -Tree 102: Descendants(Descendants { descendants: [20, 22, 24, 25, 33, 40, 46, 49, 56, 59, 62, 63, 68, 74, 78, 94, 97] }) -Tree 103: Descendants(Descendants { descendants: [2, 3, 5, 15, 16, 17, 26, 27, 28, 42, 52, 55, 57, 65, 70, 77, 79, 84, 85, 86, 88] }) -Tree 104: Descendants(Descendants { descendants: [0, 4, 6, 14, 17, 22, 23, 32, 36, 37, 40, 44, 47, 48, 50, 53, 55, 61, 64, 69, 71, 73, 85, 86, 87, 90, 94, 98, 99] }) -Tree 105: Descendants(Descendants { descendants: [3, 5, 7, 8, 11, 15, 16, 18, 19, 20, 25, 27, 29, 34, 39, 42, 57, 67, 68, 70, 72, 74, 78, 80, 83, 88, 97] }) -Tree 106: Descendants(Descendants { descendants: [1, 2, 5, 14, 20, 26, 29, 38, 43, 47, 56, 59, 60, 62, 65, 70, 72, 73, 88, 89, 91, 93, 96] }) -Tree 107: Descendants(Descendants { descendants: [0, 4, 6, 8, 11, 16, 25, 30, 32, 33, 36, 42, 46, 49, 50, 52, 67, 68, 80, 85, 90, 98] }) -Tree 108: Descendants(Descendants { descendants: [4, 6, 14, 17, 25, 26, 46, 47, 50, 52, 53, 59, 70, 74, 85, 86, 94, 96] }) -Tree 109: Descendants(Descendants { descendants: [0, 20, 22, 23, 32, 34, 37, 40, 42, 49, 55, 58, 61, 64, 71, 72, 73, 75, 76, 78, 79, 99] }) -Tree 110: SplitPlaneNormal(SplitPlaneNormal { left: 108, right: 109, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.1292" }, vector: [0.0901, 0.0157, -0.1182, 0.2329, 0.1524, -0.3723, -0.0168, -0.0950, -0.0273, -0.1918, "other ..."] } }) -Tree 111: Descendants(Descendants { descendants: [5, 7, 8, 9, 10, 11, 12, 15, 27, 33, 36, 38, 44, 48, 67, 68, 77, 87, 88, 90] }) -Tree 112: Descendants(Descendants { descendants: [1, 13, 16, 19, 28, 29, 30, 31, 35, 39, 51, 56, 57, 60, 62, 65, 69, 80, 81, 82, 92, 97, 98] }) -Tree 113: Descendants(Descendants { descendants: [2, 3, 18, 21, 24, 41, 43, 45, 54, 63, 66, 83, 84, 89, 91, 93, 95] }) -Tree 114: Descendants(Descendants { descendants: [1, 5, 10, 11, 16, 25, 28, 29, 46, 50, 52, 54, 60, 62, 65, 70, 74, 77, 85, 88, 91, 93] }) -Tree 115: Descendants(Descendants { descendants: [2, 3, 13, 18, 19, 20, 22, 24, 27, 33, 39, 42, 45, 57, 63, 66, 67, 68, 73, 78, 83, 84, 87, 89, 92, 97] }) -Tree 116: Descendants(Descendants { descendants: [10, 13, 15, 22, 27, 28, 35, 37, 48, 51, 53, 55, 57, 58, 61, 63, 66, 75, 76, 77, 78, 82, 83, 84, 87, 92, 94, 95] }) -Tree 117: Descendants(Descendants { descendants: [7, 9, 12, 18, 24, 31, 34, 39, 45, 69, 74, 86, 97, 99] }) -Tree 118: Descendants(Descendants { descendants: [1, 11, 16, 24, 29, 31, 35, 38, 43, 61, 62, 63, 65, 66, 76, 83, 89, 90, 95, 98] }) -Tree 119: Descendants(Descendants { descendants: [3, 4, 7, 9, 10, 12, 20, 21, 26, 32, 33, 51, 55, 64, 68, 72, 78, 79, 84, 97] }) -Tree 120: SplitPlaneNormal(SplitPlaneNormal { left: 118, right: 119, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.2891" }, vector: [-0.1039, 0.0459, 0.2503, -0.2181, -0.2708, 0.1290, -0.1641, 0.3678, -0.1059, 0.2104, "other ..."] } }) -Tree 121: Descendants(Descendants { descendants: [17, 28, 30, 36, 40, 41, 42, 46, 47, 49, 53, 54, 56, 57, 58, 60, 69, 70, 81, 86, 94, 99] }) -Tree 122: Descendants(Descendants { descendants: [6, 8, 17, 21, 32, 37, 48, 51, 55, 56, 61, 64, 72, 80, 82, 90, 95] }) -Tree 123: Descendants(Descendants { descendants: [0, 4, 7, 9, 15, 30, 34, 36, 38, 47, 49, 58, 69, 75, 79, 81, 94, 98, 99] }) -Tree 124: Descendants(Descendants { descendants: [12, 14, 23, 26, 31, 35, 40, 41, 43, 44, 53, 59, 71, 76, 86, 96] }) -Tree 125: SplitPlaneNormal(SplitPlaneNormal { left: 123, right: 124, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3956" }, vector: [0.1700, 0.0332, 0.1458, 0.0331, -0.0786, -0.1560, -0.0899, -0.1401, 0.2013, -0.1263, "other ..."] } }) -Tree 126: Descendants(Descendants { descendants: [12, 14, 18, 23, 37, 44, 47, 53, 55, 71, 76, 80, 94, 96, 98, 99] }) -Tree 127: Descendants(Descendants { descendants: [8, 10, 11, 17, 22, 32, 39, 52, 64, 68, 70, 74, 78, 85, 86, 97] }) -Tree 128: Descendants(Descendants { descendants: [3, 4, 7, 9, 15, 16, 26, 28, 29, 35, 38, 60, 62, 65, 69, 75, 77, 79, 88, 89, 92, 95] }) -Tree 129: SplitPlaneNormal(SplitPlaneNormal { left: 127, right: 128, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.4940" }, vector: [0.2341, -0.0005, -0.2151, -0.0487, 0.0614, -0.0621, -0.0833, 0.1284, -0.1989, -0.1540, "other ..."] } }) -Tree 130: Descendants(Descendants { descendants: [13, 20, 33, 34, 51, 62, 63, 83] }) -Tree 131: Descendants(Descendants { descendants: [0, 2, 4, 6, 21, 25, 40, 46, 47, 49, 50, 56, 57, 61, 64, 66, 67, 68, 71, 72, 73, 76, 78, 79, 80, 81, 86, 94, 95, 98] }) -Tree 132: Descendants(Descendants { descendants: [9, 13, 19, 24, 25, 30, 31, 34, 36, 39, 41, 51, 54, 60, 61, 80, 82, 83] }) -Tree 133: Descendants(Descendants { descendants: [0, 4, 11, 20, 22, 26, 28, 33, 35, 38, 46, 49, 58, 62, 63, 65, 74, 75, 94] }) -Tree 134: Descendants(Descendants { descendants: [6, 14, 29, 32, 50, 53, 56, 59, 72, 86, 88, 93, 96] }) -Tree 135: SplitPlaneNormal(SplitPlaneNormal { left: 133, right: 134, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.2576" }, vector: [0.3018, 0.1952, 0.2048, -0.3160, -0.0222, 0.2162, 0.1489, -0.0770, 0.0287, -0.1327, "other ..."] } }) -Tree 136: Descendants(Descendants { descendants: [3, 9, 10, 18, 19, 22, 26, 27, 28, 35, 37, 41, 44, 45, 54, 69, 75, 82, 84, 85, 91, 92] }) -Tree 137: Descendants(Descendants { descendants: [1, 11, 16, 29, 31, 38, 39, 60, 65, 74, 88, 97] }) -Tree 138: Descendants(Descendants { descendants: [10, 16, 17, 23, 40, 43, 48, 55, 57, 66, 68, 69, 73, 76, 78, 79, 85, 87, 95, 98, 99] }) -Tree 139: Descendants(Descendants { descendants: [1, 2, 3, 5, 7, 8, 12, 15, 18, 21, 27, 37, 42, 44, 45, 47, 52, 64, 67, 70, 71, 77, 81, 84, 89, 90, 91, 92, 97] }) -Tree 140: Descendants(Descendants { descendants: [7, 8, 12, 13, 20, 21, 24, 39, 45, 51, 52, 66, 80, 89, 93, 95] }) -Tree 141: Descendants(Descendants { descendants: [1, 2, 3, 10, 18, 27, 29, 37, 47, 50, 57, 63, 65, 67, 68, 72, 73, 74, 78, 82, 84, 88, 92, 96, 97] }) -Tree 142: Descendants(Descendants { descendants: [4, 7, 9, 10, 11, 18, 29, 30, 31, 39, 44, 45, 48, 51, 60, 66, 67, 81, 82, 89, 92, 95, 96] }) -Tree 143: Descendants(Descendants { descendants: [6, 8, 12, 21, 32, 37, 50, 72, 90, 91, 93] }) -Tree 144: Descendants(Descendants { descendants: [1, 9, 24, 31, 35, 38, 49, 56, 58, 62, 75, 76, 81, 92, 96] }) -Tree 145: Descendants(Descendants { descendants: [2, 10, 12, 13, 21, 26, 28, 30, 33, 41, 43, 45, 46, 51, 52, 54, 59, 60, 63, 65, 66, 77, 79, 82, 84, 89, 91, 93, 95] }) -Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5691, 0.2017, 0.2038, 0.2523, 0.1656, 0.7198, 0.9908, 0.9873, 0.1991, 0.2202, "other ..."] }) +Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 88, right: 91, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3733" }, vector: [-0.0475, -0.1496, 0.1344, -0.1902, -0.2161, -0.4158, -0.1593, 0.1212, -0.0136, 0.2277, "other ..."] } }) +Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 76, right: 81, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.4143" }, vector: [-0.1850, 0.1162, 0.1506, 0.1488, 0.2308, 0.1370, -0.2152, -0.0274, -0.0407, -0.2282, "other ..."] } }) +Tree 2: SplitPlaneNormal(SplitPlaneNormal { left: 66, right: 73, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0804" }, vector: [0.1941, -0.1680, -0.0860, -0.4588, 0.2054, 0.0884, 0.0622, 0.1314, 0.1377, -0.2936, "other ..."] } }) +Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 58, right: 63, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0458" }, vector: [-0.0598, -0.0926, -0.1871, -0.0077, 0.2839, 0.2008, 0.1168, -0.3345, -0.0870, 0.0621, "other ..."] } }) +Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 50, right: 53, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0933" }, vector: [-0.2249, -0.2354, -0.2492, 0.0508, -0.0488, 0.3083, 0.0932, -0.0190, -0.4116, -0.0404, "other ..."] } }) +Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 38, right: 45, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0963" }, vector: [0.0636, -0.2729, 0.4830, 0.1626, 0.0343, -0.0273, -0.0742, 0.0450, -0.3975, -0.3293, "other ..."] } }) +Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 32, right: 35, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.6869" }, vector: [0.0755, 0.2682, -0.0986, 0.3341, 0.0086, -0.0666, -0.2590, -0.1551, 0.0651, -0.0362, "other ..."] } }) +Tree 7: SplitPlaneNormal(SplitPlaneNormal { left: 26, right: 29, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0797" }, vector: [-0.0053, 0.4627, 0.0033, -0.1321, 0.2763, -0.0670, -0.0985, -0.1405, 0.3819, 0.0681, "other ..."] } }) +Tree 8: SplitPlaneNormal(SplitPlaneNormal { left: 22, right: 23, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3843" }, vector: [-0.3055, 0.2263, 0.3598, -0.0777, -0.0538, -0.1513, -0.0809, 0.1401, 0.0514, 0.2712, "other ..."] } }) +Tree 9: SplitPlaneNormal(SplitPlaneNormal { left: 12, right: 17, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.9466" }, vector: [-0.1459, -0.2139, -0.2989, 0.0100, -0.1856, -0.0497, 0.1403, 0.0371, -0.2027, 0.1831, "other ..."] } }) +Tree 12: SplitPlaneNormal(SplitPlaneNormal { left: 118, right: 119, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9158" }, vector: [-0.0458, 0.2305, 0.1661, 0.0458, -0.2590, -0.1403, 0.2607, 0.4083, 0.4034, -0.0825, "other ..."] } }) +Tree 15: SplitPlaneNormal(SplitPlaneNormal { left: 116, right: 117, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.6717" }, vector: [0.2202, -0.1642, -0.2834, -0.0990, 0.0846, -0.0629, -0.0479, -0.1356, -0.1214, -0.0144, "other ..."] } }) +Tree 16: Descendants(Descendants { descendants: [1, 4, 5, 7, 9, 20, 29, 31, 34, 35, 42, 49, 53, 58, 63, 65, 69, 75, 82, 83, 90, 94, 97] }) +Tree 17: SplitPlaneNormal(SplitPlaneNormal { left: 15, right: 16, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3772" }, vector: [0.1033, -0.4242, -0.0800, -0.1632, 0.1052, -0.0050, 0.2207, -0.1568, -0.0534, -0.0278, "other ..."] } }) +Tree 20: SplitPlaneNormal(SplitPlaneNormal { left: 104, right: 105, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3104" }, vector: [0.0826, -0.5362, 0.1182, -0.0236, -0.1482, -0.0931, 0.1951, -0.2227, -0.1086, -0.0982, "other ..."] } }) +Tree 21: SplitPlaneNormal(SplitPlaneNormal { left: 102, right: 103, normal: Leaf { header: NodeHeaderEuclidean { bias: "-1.0630" }, vector: [-0.0780, 0.1337, 0.4574, 0.0526, 0.1908, 0.0708, -0.0698, -0.1701, 0.1157, 0.0710, "other ..."] } }) +Tree 22: SplitPlaneNormal(SplitPlaneNormal { left: 20, right: 21, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.2139" }, vector: [0.0683, -0.0814, 0.0252, -0.1067, -0.2097, -0.0424, 0.1001, 0.3194, 0.0825, 0.0236, "other ..."] } }) +Tree 23: Descendants(Descendants { descendants: [1, 3, 5, 6, 7, 9, 15, 17, 26, 27, 32, 39, 44, 53, 60, 69, 73, 79, 81, 90, 92, 96] }) +Tree 26: SplitPlaneNormal(SplitPlaneNormal { left: 94, right: 95, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.2166" }, vector: [-0.1899, 0.2916, 0.3346, 0.0524, 0.0863, -0.2032, -0.0673, -0.0062, -0.1249, -0.0454, "other ..."] } }) +Tree 27: Descendants(Descendants { descendants: [2, 8, 17, 19, 23, 27, 32, 40, 41, 45, 47, 52, 53, 54, 55, 56, 64, 70, 71, 72, 73, 74, 76, 77, 78, 79, 80, 91, 97, 99] }) +Tree 28: SplitPlaneNormal(SplitPlaneNormal { left: 96, right: 97, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.2331" }, vector: [-0.0662, -0.0246, 0.0656, -0.1624, -0.0047, -0.2392, 0.2543, 0.0888, 0.0744, -0.0221, "other ..."] } }) +Tree 29: SplitPlaneNormal(SplitPlaneNormal { left: 27, right: 28, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3445" }, vector: [0.0543, -0.0671, 0.0759, 0.0437, -0.0054, -0.0953, 0.1007, 0.0988, 0.0009, -0.2796, "other ..."] } }) +Tree 32: SplitPlaneNormal(SplitPlaneNormal { left: 140, right: 141, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3528" }, vector: [-0.1255, 0.2100, 0.2201, -0.0886, -0.0719, 0.1535, -0.0794, -0.3796, -0.0068, 0.0762, "other ..."] } }) +Tree 35: SplitPlaneNormal(SplitPlaneNormal { left: 136, right: 137, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0092" }, vector: [0.0108, -0.0562, 0.4257, 0.0562, -0.1473, 0.0892, -0.1165, -0.0178, -0.1477, -0.1727, "other ..."] } }) +Tree 38: SplitPlaneNormal(SplitPlaneNormal { left: 130, right: 131, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.5951" }, vector: [-0.2909, 0.2667, 0.1728, 0.0055, -0.1251, -0.1814, 0.1971, 0.2927, -0.0904, 0.0955, "other ..."] } }) +Tree 45: SplitPlaneNormal(SplitPlaneNormal { left: 122, right: 123, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.7796" }, vector: [0.2439, 0.1112, 0.0842, 0.0732, -0.1858, 0.1108, 0.1022, -0.0101, -0.0240, 0.0866, "other ..."] } }) +Tree 50: SplitPlaneNormal(SplitPlaneNormal { left: 112, right: 113, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0886" }, vector: [-0.1092, 0.0967, -0.4147, 0.2370, 0.0932, -0.1638, 0.3286, -0.0270, -0.0593, 0.2244, "other ..."] } }) +Tree 53: SplitPlaneNormal(SplitPlaneNormal { left: 106, right: 109, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0112" }, vector: [0.2581, -0.1616, 0.0520, -0.0158, -0.0994, -0.1019, -0.2418, -0.0599, 0.0749, 0.0170, "other ..."] } }) +Tree 58: SplitPlaneNormal(SplitPlaneNormal { left: 100, right: 101, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.5915" }, vector: [0.1357, 0.1271, 0.4036, -0.1687, -0.1611, -0.3156, -0.0362, 0.0930, -0.0564, 0.1692, "other ..."] } }) +Tree 61: SplitPlaneNormal(SplitPlaneNormal { left: 92, right: 93, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0411" }, vector: [0.1302, 0.1023, -0.0111, 0.0435, -0.0185, -0.2444, -0.3379, -0.0689, 0.1791, 0.0961, "other ..."] } }) +Tree 62: Descendants(Descendants { descendants: [7, 10, 11, 13, 19, 31, 33, 45, 54, 56, 62, 65, 69, 84, 91, 94, 97] }) +Tree 63: SplitPlaneNormal(SplitPlaneNormal { left: 61, right: 62, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3949" }, vector: [-0.0495, 0.0658, 0.2323, 0.1854, 0.3495, -0.0897, -0.1301, -0.1341, -0.1506, -0.0808, "other ..."] } }) +Tree 66: SplitPlaneNormal(SplitPlaneNormal { left: 138, right: 139, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0191" }, vector: [0.1925, 0.1837, 0.2125, -0.1185, 0.0735, -0.2200, -0.0427, 0.0901, -0.2491, 0.0148, "other ..."] } }) +Tree 67: Descendants(Descendants { descendants: [10, 17, 21, 26, 36, 37, 40, 41, 47, 59, 60, 68, 74, 76, 77, 85, 96, 98] }) +Tree 72: SplitPlaneNormal(SplitPlaneNormal { left: 128, right: 129, normal: Leaf { header: NodeHeaderEuclidean { bias: "-1.4394" }, vector: [0.1356, 0.0893, 0.1515, -0.0121, 0.0644, -0.1414, -0.2150, 0.3689, 0.2727, 0.3711, "other ..."] } }) +Tree 73: SplitPlaneNormal(SplitPlaneNormal { left: 67, right: 72, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.1344" }, vector: [0.0129, 0.2435, 0.2349, -0.0484, 0.2422, -0.2681, 0.1833, -0.1857, -0.3249, -0.1537, "other ..."] } }) +Tree 76: SplitPlaneNormal(SplitPlaneNormal { left: 126, right: 127, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0400" }, vector: [-0.1900, -0.2147, -0.0647, 0.0511, -0.4092, 0.2976, -0.0874, 0.1915, 0.0428, -0.0973, "other ..."] } }) +Tree 81: SplitPlaneNormal(SplitPlaneNormal { left: 114, right: 115, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0927" }, vector: [0.1306, -0.2980, 0.1347, 0.1086, -0.0555, -0.0421, -0.3452, 0.0438, -0.0418, -0.2373, "other ..."] } }) +Tree 84: SplitPlaneNormal(SplitPlaneNormal { left: 110, right: 111, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.2518" }, vector: [-0.1457, 0.0668, -0.0585, 0.3369, -0.3826, 0.0071, 0.1223, -0.0799, -0.1587, 0.1256, "other ..."] } }) +Tree 87: Descendants(Descendants { descendants: [0, 1, 10, 11, 13, 19, 26, 27, 30, 31, 33, 45, 46, 47, 48, 50, 54, 56, 62, 65, 70, 72, 82, 91, 97] }) +Tree 88: SplitPlaneNormal(SplitPlaneNormal { left: 84, right: 87, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0201" }, vector: [-0.1124, 0.1501, 0.1593, 0.1114, 0.1879, 0.1623, -0.2202, -0.1170, -0.3266, 0.2916, "other ..."] } }) +Tree 91: SplitPlaneNormal(SplitPlaneNormal { left: 98, right: 99, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9950" }, vector: [-0.0869, 0.1981, 0.2025, -0.1256, 0.0042, -0.2087, 0.3637, 0.0604, 0.0826, -0.1302, "other ..."] } }) +Tree 92: Descendants(Descendants { descendants: [5, 20, 25, 38, 41, 42, 44, 49, 51, 59, 64, 68, 75, 78, 83, 87, 88] }) +Tree 93: Descendants(Descendants { descendants: [0, 2, 8, 16, 17, 23, 27, 34, 35, 36, 40, 48, 50, 52, 53, 55, 58, 63, 67, 72, 73, 74, 80, 82, 85, 99] }) +Tree 94: Descendants(Descendants { descendants: [0, 1, 7, 11, 25, 28, 29, 30, 31, 34, 35, 46, 49, 58, 62, 63, 65, 66, 69, 82] }) +Tree 95: Descendants(Descendants { descendants: [4, 5, 6, 10, 14, 15, 16, 22, 33, 42, 59, 83, 86, 89, 92, 93, 94, 96] }) +Tree 96: Descendants(Descendants { descendants: [12, 13, 20, 21, 26, 36, 39, 43, 48, 50, 51, 57, 60, 61, 81, 85, 90, 95, 98] }) +Tree 97: Descendants(Descendants { descendants: [3, 9, 18, 24, 37, 38, 44, 67, 68, 75, 84, 87, 88] }) +Tree 98: Descendants(Descendants { descendants: [6, 28, 29, 76, 77, 84, 89, 90, 92] }) +Tree 99: Descendants(Descendants { descendants: [3, 4, 5, 7, 9, 15, 18, 22, 23, 24, 32, 35, 39, 44, 53, 55, 57, 59, 60, 63, 66, 81, 83, 86, 95, 96] }) +Tree 100: Descendants(Descendants { descendants: [12, 14, 24, 29, 30, 43, 47, 57, 61, 70] }) +Tree 101: Descendants(Descendants { descendants: [1, 3, 4, 6, 9, 15, 18, 21, 22, 26, 28, 32, 37, 39, 46, 60, 66, 71, 76, 77, 79, 81, 86, 89, 90, 92, 93, 95, 96, 98] }) +Tree 102: Descendants(Descendants { descendants: [0, 2, 10, 11, 14, 20, 24, 25, 28, 29, 37, 41, 42, 46, 55, 57, 58, 72, 76, 77, 84, 85, 86, 91, 93, 95, 99] }) +Tree 103: Descendants(Descendants { descendants: [8, 40, 52, 54, 56, 67, 74, 97, 98] }) +Tree 104: Descendants(Descendants { descendants: [12, 13, 16, 19, 21, 22, 23, 38, 43, 47, 48, 61, 64, 68, 70, 71, 78, 80, 87, 88] }) +Tree 105: Descendants(Descendants { descendants: [4, 18, 30, 31, 33, 34, 35, 36, 45, 49, 50, 51, 59, 62, 63, 65, 66, 75, 82, 83, 89, 94] }) +Tree 106: Descendants(Descendants { descendants: [5, 12, 13, 20, 38, 42, 61, 83, 87, 88, 90] }) +Tree 107: Descendants(Descendants { descendants: [0, 1, 2, 25, 27, 28, 29, 30, 41, 57, 58, 65, 68, 85, 92, 93] }) +Tree 108: Descendants(Descendants { descendants: [4, 7, 9, 22, 31, 33, 34, 45, 47, 48, 51, 54, 62, 78, 81, 82, 95, 97] }) +Tree 109: SplitPlaneNormal(SplitPlaneNormal { left: 107, right: 108, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0140" }, vector: [0.2537, 0.4037, -0.0105, -0.2316, 0.3283, 0.0570, -0.0756, -0.0590, -0.1890, 0.0121, "other ..."] } }) +Tree 110: Descendants(Descendants { descendants: [2, 8, 12, 20, 21, 25, 36, 37, 40, 41, 43, 51, 52, 61, 67, 68, 71, 78, 85, 88, 98] }) +Tree 111: Descendants(Descendants { descendants: [14, 16, 17, 34, 38, 42, 49, 58, 64, 69, 73, 74, 75, 79, 80, 87, 93, 94, 99] }) +Tree 112: Descendants(Descendants { descendants: [3, 8, 10, 11, 15, 18, 21, 24, 26, 39, 40, 46, 52, 56, 59, 60, 66, 67, 76, 77, 79, 84, 89, 91, 96, 98] }) +Tree 113: Descendants(Descendants { descendants: [6, 14, 16, 17, 19, 23, 32, 35, 36, 37, 43, 44, 49, 50, 53, 55, 63, 64, 69, 70, 71, 72, 73, 74, 75, 80, 86, 94, 99] }) +Tree 114: Descendants(Descendants { descendants: [3, 4, 5, 8, 9, 12, 13, 17, 27, 40, 45, 51, 54, 61, 65, 67, 73, 77, 85, 87, 88] }) +Tree 115: Descendants(Descendants { descendants: [0, 2, 7, 10, 11, 19, 24, 25, 29, 31, 33, 39, 41, 48, 50, 52, 56, 58, 66, 74, 81, 84, 86, 91, 92, 93, 96, 97, 98] }) +Tree 116: Descendants(Descendants { descendants: [3, 8, 15, 17, 18, 24, 27, 30, 44, 57, 60, 61, 68, 78, 79, 81] }) +Tree 117: Descendants(Descendants { descendants: [0, 2, 14, 22, 23, 25, 28, 33, 37, 38, 46, 47, 55, 64, 70, 71, 73, 76, 80, 84, 86, 87, 92, 95, 99] }) +Tree 118: Descendants(Descendants { descendants: [6, 10, 11, 12, 13, 16, 19, 36, 39, 40, 41, 45, 48, 50, 51, 52, 54, 56, 59, 62, 67, 72, 74, 77, 85, 89, 91] }) +Tree 119: Descendants(Descendants { descendants: [21, 26, 32, 43, 66, 88, 93, 96, 98] }) +Tree 120: Descendants(Descendants { descendants: [2, 7, 13, 20, 24, 25, 30, 33, 34, 42, 51, 60, 66, 67, 72, 99] }) +Tree 121: Descendants(Descendants { descendants: [0, 5, 6, 10, 11, 15, 16, 18, 35, 49, 56, 59, 69, 75, 83, 84, 90] }) +Tree 122: SplitPlaneNormal(SplitPlaneNormal { left: 120, right: 121, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3399" }, vector: [-0.2135, 0.0117, 0.1496, -0.1049, 0.0717, -0.0390, -0.1250, 0.0523, 0.2200, 0.0932, "other ..."] } }) +Tree 123: Descendants(Descendants { descendants: [1, 4, 9, 29, 31, 39, 45, 46, 50, 58, 62, 63, 65, 82, 86, 89, 92, 93, 96, 97] }) +Tree 124: Descendants(Descendants { descendants: [14, 16, 18, 20, 32, 35, 36, 37, 38, 42, 43, 53, 55, 57, 59, 62, 71, 75, 78, 80, 94, 95] }) +Tree 125: Descendants(Descendants { descendants: [6, 15, 22, 23, 44, 60, 63, 69, 70, 72, 79, 83, 89, 90, 99] }) +Tree 126: SplitPlaneNormal(SplitPlaneNormal { left: 124, right: 125, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.2654" }, vector: [-0.0413, 0.0551, 0.3348, -0.0135, 0.0135, 0.0968, -0.4112, 0.2955, -0.1179, 0.3146, "other ..."] } }) +Tree 127: Descendants(Descendants { descendants: [1, 21, 26, 28, 30, 34, 46, 47, 49, 64, 68, 76, 82] }) +Tree 128: Descendants(Descendants { descendants: [4, 5, 6, 12, 13, 14, 18, 19, 20, 22, 38, 42, 44, 45, 51, 61, 64, 65, 73, 75, 78, 80, 83, 87, 90] }) +Tree 129: Descendants(Descendants { descendants: [11, 15, 16, 23, 24, 34, 35, 39, 43, 49, 50, 52, 53, 55, 62, 63, 66, 67, 69, 70, 71, 72, 84, 86, 88, 94] }) +Tree 130: Descendants(Descendants { descendants: [14, 19, 23, 26, 28, 36, 40, 41, 43, 48, 52, 53, 55, 61, 70, 71, 74, 76, 78, 85, 91, 94, 98] }) +Tree 131: Descendants(Descendants { descendants: [3, 8, 12, 17, 21, 22, 27, 32, 37, 38, 44, 47, 54, 57, 64, 68, 73, 77, 79, 80, 81, 87, 88, 95] }) +Tree 132: Descendants(Descendants { descendants: [11, 18, 19, 64, 68, 76, 81, 91] }) +Tree 133: Descendants(Descendants { descendants: [2, 8, 16, 23, 27, 28, 32, 36, 37, 45, 48, 50, 55, 57, 63, 70, 72, 73, 74, 79, 80, 84, 86, 87, 95] }) +Tree 134: SplitPlaneNormal(SplitPlaneNormal { left: 132, right: 133, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3133" }, vector: [0.3021, 0.1322, 0.0217, -0.1230, 0.2695, -0.2384, 0.2780, -0.0483, -0.1448, 0.1303, "other ..."] } }) +Tree 135: Descendants(Descendants { descendants: [3, 12, 52, 61, 67, 97] }) +Tree 136: SplitPlaneNormal(SplitPlaneNormal { left: 134, right: 135, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.6145" }, vector: [-0.2144, -0.0469, 0.2871, -0.2047, 0.1997, 0.2381, -0.0809, 0.4253, 0.0301, -0.0456, "other ..."] } }) +Tree 137: Descendants(Descendants { descendants: [1, 6, 7, 13, 21, 26, 46, 47, 54, 56, 62, 77, 89, 90, 93, 98] }) +Tree 138: Descendants(Descendants { descendants: [0, 2, 8, 25, 27, 28, 30, 32, 46, 54, 56, 57, 58, 79, 81, 91, 92, 99] }) +Tree 139: Descendants(Descendants { descendants: [1, 3, 7, 9, 29, 31, 33, 48, 82, 89, 93, 95, 97] }) +Tree 140: Descendants(Descendants { descendants: [4, 9, 14, 22, 25, 29, 30, 35, 39, 42, 43, 58, 65, 66, 69, 83, 85, 88, 92, 96] }) +Tree 141: Descendants(Descendants { descendants: [0, 5, 10, 15, 17, 20, 24, 31, 33, 34, 38, 40, 41, 44, 49, 51, 53, 59, 60, 71, 75, 78, 82, 94, 99] }) +Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.2240, 0.0136, 0.1967, 0.7482, 0.6849, 0.7949, 0.0809, 0.5504, 0.6339, 0.6978, "other ..."] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4199, 0.2620, 0.2655, 0.8414, 0.0192, 0.3828, 0.2561, 0.2692, 0.0368, 0.4624, "other ..."] }) -Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.9844, 0.4436, 0.6281, 0.0342, 0.3575, 0.3818, 0.0302, 0.0269, 0.2284, 0.6082, "other ..."] }) +Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7711, 0.4016, 0.1489, 0.9991, 0.5236, 0.5613, 0.4596, 0.2214, 0.5016, 0.1191, "other ..."] }) Item 3: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0001, 0.7870, 0.9674, 0.4568, 0.5250, 0.2701, 0.2417, 0.8742, 0.6869, 0.8759, "other ..."] }) -Item 4: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6305, 0.1852, 0.0517, 0.5162, 0.4308, 0.9393, 0.3359, 0.8628, 0.0185, 0.6288, "other ..."] }) +Item 4: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7473, 0.3347, 0.9786, 0.4693, 0.3540, 0.1280, 0.9628, 0.2076, 0.3437, 0.4589, "other ..."] }) Item 5: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0850, 0.7778, 0.8818, 0.3427, 0.1293, 0.7240, 0.4773, 0.2871, 0.3988, 0.4014, "other ..."] }) -Item 6: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7732, 0.4859, 0.6940, 0.7124, 0.1809, 0.9183, 0.8297, 0.2409, 0.2959, 0.3889, "other ..."] }) +Item 6: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1874, 0.7676, 0.9707, 0.5148, 0.7242, 0.4714, 0.1278, 0.2181, 0.2651, 0.5674, "other ..."] }) Item 7: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5699, 0.5919, 0.7788, 0.3705, 0.3807, 0.1708, 0.3678, 0.5629, 0.0612, 0.4826, "other ..."] }) -Item 8: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.2606, 0.1377, 0.7441, 0.0135, 0.0619, 0.4194, 0.5945, 0.9413, 0.2151, 0.5847, "other ..."] }) +Item 8: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.3157, 0.8096, 0.5024, 0.5421, 0.4327, 0.3696, 0.6485, 0.7972, 0.9792, 0.9554, "other ..."] }) Item 9: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8134, 0.9647, 0.6640, 0.4464, 0.7439, 0.6904, 0.3159, 0.7607, 0.3483, 0.9963, "other ..."] }) -Item 10: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0801, 0.9351, 0.7265, 0.8319, 0.4562, 0.3787, 0.7330, 0.9286, 0.1837, 0.8404, "other ..."] }) +Item 10: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1559, 0.1898, 0.2475, 0.4582, 0.5481, 0.5846, 0.1844, 0.4898, 0.2916, 0.2669, "other ..."] }) Item 11: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6560, 0.2343, 0.4079, 0.5972, 0.5766, 0.6739, 0.2985, 0.6167, 0.4834, 0.2818, "other ..."] }) -Item 12: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.9924, 0.5685, 0.3723, 0.2297, 0.1589, 0.7127, 0.7569, 0.8008, 0.2684, 0.8629, "other ..."] }) +Item 12: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1712, 0.6340, 0.2866, 0.6282, 0.9072, 0.7589, 0.6432, 0.8676, 0.2942, 0.4375, "other ..."] }) Item 13: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1726, 0.7399, 0.0271, 0.8721, 0.8725, 0.4023, 0.1558, 0.1044, 0.2096, 0.2081, "other ..."] }) -Item 14: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5341, 0.5373, 0.3614, 0.1611, 0.7268, 0.7789, 0.5822, 0.5474, 0.7846, 0.3485, "other ..."] }) +Item 14: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8145, 0.6759, 0.1411, 0.7878, 0.3556, 0.8440, 0.5301, 0.2627, 0.7050, 0.4145, "other ..."] }) Item 15: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6031, 0.2970, 0.9485, 0.0272, 0.4336, 0.1339, 0.2209, 0.8350, 0.2566, 0.9481, "other ..."] }) -Item 16: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6272, 0.7204, 0.4137, 0.3103, 0.8987, 0.1995, 0.9046, 0.4746, 0.5808, 0.6296, "other ..."] }) +Item 16: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4594, 0.9245, 0.5151, 0.7390, 0.6121, 0.5891, 0.5795, 0.6295, 0.0595, 0.6471, "other ..."] }) Item 17: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0819, 0.5362, 0.8215, 0.2263, 0.3109, 0.2738, 0.6133, 0.5147, 0.9334, 0.9877, "other ..."] }) -Item 18: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4160, 0.5313, 0.4760, 0.2117, 0.7608, 0.2017, 0.5997, 0.4663, 0.2783, 0.8645, "other ..."] }) +Item 18: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5102, 0.8700, 0.3910, 0.0807, 0.1067, 0.0692, 0.7037, 0.4229, 0.0066, 0.1894, "other ..."] }) Item 19: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1390, 0.7531, 0.3249, 0.8754, 0.9984, 0.7362, 0.0281, 0.2016, 0.9443, 0.1989, "other ..."] }) -Item 20: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8596, 0.0010, 0.8143, 0.8791, 0.7726, 0.7088, 0.0896, 0.3240, 0.1309, 0.5004, "other ..."] }) +Item 20: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8077, 0.3229, 0.5031, 0.0472, 0.6957, 0.9603, 0.8790, 0.2009, 0.3837, 0.1765, "other ..."] }) Item 21: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6252, 0.9240, 0.7227, 0.6810, 0.2563, 0.3321, 0.2283, 0.9226, 0.8494, 0.0356, "other ..."] }) -Item 22: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1915, 0.2687, 0.7671, 0.6234, 0.9868, 0.7270, 0.5404, 0.6695, 0.9427, 0.5441, "other ..."] }) +Item 22: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1651, 0.4144, 0.2816, 0.0037, 0.3038, 0.2344, 0.3321, 0.1985, 0.4704, 0.3710, "other ..."] }) Item 23: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.9915, 0.6886, 0.1976, 0.1725, 0.6776, 0.1356, 0.3842, 0.4424, 0.6939, 0.8016, "other ..."] }) -Item 24: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4766, 0.1355, 0.7071, 0.8291, 0.7740, 0.3245, 0.2792, 0.0711, 0.6141, 0.7858, "other ..."] }) +Item 24: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7192, 0.5087, 0.9102, 0.0269, 0.7119, 0.7909, 0.0259, 0.6221, 0.9168, 0.1528, "other ..."] }) Item 25: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0116, 0.5323, 0.3940, 0.1382, 0.1987, 0.7287, 0.4026, 0.1442, 0.5957, 0.0340, "other ..."] }) -Item 26: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.9958, 0.2017, 0.2902, 0.3911, 0.0928, 0.5717, 0.3145, 0.7503, 0.4984, 0.9545, "other ..."] }) +Item 26: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5587, 0.8792, 0.9279, 0.4203, 0.9903, 0.7524, 0.0600, 0.9020, 0.8837, 0.1950, "other ..."] }) Item 27: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.3569, 0.9070, 0.8412, 0.3201, 0.6998, 0.8674, 0.5494, 0.2322, 0.2969, 0.9787, "other ..."] }) -Item 28: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1562, 0.4070, 0.0880, 0.9745, 0.7060, 0.0318, 0.7282, 0.6670, 0.8390, 0.2992, "other ..."] }) +Item 28: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.9353, 0.1703, 0.1992, 0.7788, 0.4769, 0.5431, 0.4292, 0.5249, 0.7629, 0.9059, "other ..."] }) Item 29: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6021, 0.0690, 0.1080, 0.2535, 0.6817, 0.7899, 0.3297, 0.8656, 0.1566, 0.3560, "other ..."] }) -Item 30: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6452, 0.9110, 0.7132, 0.4191, 0.4112, 0.5348, 0.4404, 0.8581, 0.4330, 0.8951, "other ..."] }) +Item 30: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.3473, 0.1415, 0.1873, 0.7472, 0.3808, 0.6412, 0.1944, 0.5869, 0.0722, 0.3215, "other ..."] }) Item 31: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7584, 0.3448, 0.7315, 0.5405, 0.6797, 0.3253, 0.8611, 0.0846, 0.0174, 0.0882, "other ..."] }) -Item 32: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6471, 0.6307, 0.8962, 0.2893, 0.4631, 0.1205, 0.7605, 0.8382, 0.9778, 0.0805, "other ..."] }) +Item 32: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4076, 0.8830, 0.7654, 0.5911, 0.3055, 0.0942, 0.7024, 0.9471, 0.9752, 0.4628, "other ..."] }) Item 33: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.3494, 0.5787, 0.8027, 0.9625, 0.5944, 0.6781, 0.4204, 0.5899, 0.0209, 0.9001, "other ..."] }) -Item 34: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4709, 0.1850, 0.4666, 0.4263, 0.6792, 0.7046, 0.0851, 0.2056, 0.7178, 0.4810, "other ..."] }) +Item 34: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6939, 0.0973, 0.2992, 0.4254, 0.0919, 0.8203, 0.3851, 0.0823, 0.4547, 0.4283, "other ..."] }) Item 35: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.3281, 0.1178, 0.0533, 0.4172, 0.3990, 0.0395, 0.8533, 0.1435, 0.9799, 0.4063, "other ..."] }) -Item 36: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0761, 0.8969, 0.0492, 0.2230, 0.4939, 0.5646, 0.6062, 0.4992, 0.1078, 0.5006, "other ..."] }) +Item 36: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7093, 0.6425, 0.0423, 0.0877, 0.7820, 0.6701, 0.4963, 0.1499, 0.8631, 0.8113, "other ..."] }) Item 37: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6603, 0.3675, 0.1019, 0.2193, 0.3180, 0.0591, 0.9934, 0.8583, 0.7473, 0.3644, "other ..."] }) -Item 38: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1991, 0.5403, 0.0405, 0.1756, 0.8858, 0.4640, 0.9576, 0.3734, 0.2786, 0.0953, "other ..."] }) +Item 38: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0152, 0.9782, 0.0253, 0.6194, 0.6177, 0.6446, 0.8634, 0.8343, 0.1429, 0.6369, "other ..."] }) Item 39: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4498, 0.4107, 0.9992, 0.3928, 0.4779, 0.4661, 0.1282, 0.8140, 0.7490, 0.5641, "other ..."] }) -Item 40: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4070, 0.1137, 0.5368, 0.9245, 0.2500, 0.0250, 0.7935, 0.0007, 0.7585, 0.4630, "other ..."] }) +Item 40: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5514, 0.2225, 0.8400, 0.2598, 0.5622, 0.6231, 0.5772, 0.0082, 0.8470, 0.9596, "other ..."] }) Item 41: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7821, 0.0623, 0.1168, 0.3609, 0.6040, 0.8336, 0.0911, 0.2181, 0.7485, 0.0281, "other ..."] }) -Item 42: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5091, 0.0906, 0.6799, 0.0227, 0.0664, 0.4943, 0.6480, 0.2907, 0.1529, 0.9099, "other ..."] }) +Item 42: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.9144, 0.0223, 0.5079, 0.6873, 0.5501, 0.2577, 0.9304, 0.3154, 0.1546, 0.3749, "other ..."] }) Item 43: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8608, 0.8689, 0.4918, 0.2239, 0.9291, 0.0622, 0.6843, 0.4184, 0.4703, 0.3202, "other ..."] }) -Item 44: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8975, 0.9026, 0.3267, 0.2830, 0.9081, 0.1656, 0.4371, 0.8825, 0.9425, 0.4156, "other ..."] }) +Item 44: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5159, 0.9516, 0.6267, 0.1007, 0.4283, 0.1452, 0.9565, 0.4723, 0.4935, 0.7395, "other ..."] }) Item 45: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.9838, 0.4742, 0.5307, 0.6989, 0.9323, 0.2140, 0.1371, 0.1113, 0.0322, 0.3001, "other ..."] }) -Item 46: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.3753, 0.2408, 0.2653, 0.7672, 0.0966, 0.2104, 0.2312, 0.3469, 0.6364, 0.3652, "other ..."] }) +Item 46: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.3709, 0.3974, 0.5971, 0.7814, 0.2075, 0.5392, 0.4790, 0.5432, 0.4844, 0.3367, "other ..."] }) Item 47: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4506, 0.8658, 0.1164, 0.2339, 0.2266, 0.9050, 0.5849, 0.9792, 0.5951, 0.7706, "other ..."] }) -Item 48: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5486, 0.9838, 0.6668, 0.1541, 0.6342, 0.9678, 0.9183, 0.4694, 0.4923, 0.5748, "other ..."] }) +Item 48: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7462, 0.9877, 0.0796, 0.4441, 0.9824, 0.6855, 0.0985, 0.0618, 0.0551, 0.5251, "other ..."] }) Item 49: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1322, 0.0670, 0.3404, 0.5339, 0.0229, 0.5964, 0.5497, 0.3819, 0.6553, 0.7129, "other ..."] }) -Item 50: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7915, 0.8245, 0.0562, 0.0983, 0.1049, 0.9047, 0.3248, 0.8740, 0.7597, 0.5026, "other ..."] }) +Item 50: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8421, 0.8103, 0.5294, 0.6795, 0.9634, 0.3110, 0.8945, 0.1541, 0.5916, 0.1082, "other ..."] }) Item 51: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.3643, 0.3282, 0.2580, 0.4477, 0.5920, 0.3581, 0.3502, 0.2441, 0.1707, 0.1243, "other ..."] }) -Item 52: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4767, 0.5844, 0.9410, 0.8368, 0.3227, 0.7505, 0.1099, 0.8573, 0.7832, 0.9095, "other ..."] }) +Item 52: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8491, 0.4500, 0.8568, 0.1146, 0.7974, 0.5148, 0.0862, 0.6020, 0.7705, 0.6189, "other ..."] }) Item 53: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5928, 0.6267, 0.1717, 0.1604, 0.6506, 0.0302, 0.8289, 0.5930, 0.9304, 0.6067, "other ..."] }) -Item 54: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5760, 0.3888, 0.2231, 0.5688, 0.4859, 0.2078, 0.1466, 0.3177, 0.9709, 0.6116, "other ..."] }) +Item 54: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.2720, 0.7143, 0.6966, 0.9709, 0.4263, 0.7441, 0.8624, 0.1372, 0.0418, 0.7771, "other ..."] }) Item 55: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6095, 0.6335, 0.4740, 0.0746, 0.3871, 0.1016, 0.6414, 0.3076, 0.5484, 0.7602, "other ..."] }) -Item 56: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.2802, 0.2739, 0.7232, 0.8222, 0.4219, 0.5532, 0.3637, 0.2164, 0.9099, 0.0570, "other ..."] }) +Item 56: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4278, 0.5749, 0.9222, 0.8668, 0.5708, 0.7825, 0.1484, 0.1654, 0.7721, 0.1671, "other ..."] }) Item 57: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1524, 0.3441, 0.2368, 0.4350, 0.5328, 0.3005, 0.7021, 0.3614, 0.6369, 0.7984, "other ..."] }) -Item 58: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0312, 0.3130, 0.1591, 0.7236, 0.5735, 0.2308, 0.5460, 0.3421, 0.0572, 0.6052, "other ..."] }) +Item 58: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5174, 0.1043, 0.5020, 0.7082, 0.0108, 0.7768, 0.2805, 0.5635, 0.1165, 0.3446, "other ..."] }) Item 59: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6227, 0.1202, 0.9715, 0.3936, 0.3423, 0.7479, 0.6526, 0.1867, 0.5568, 0.0922, "other ..."] }) -Item 60: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5270, 0.0955, 0.5762, 0.0805, 0.3199, 0.9090, 0.6208, 0.8156, 0.2419, 0.3181, "other ..."] }) +Item 60: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7594, 0.3160, 0.8848, 0.2336, 0.2080, 0.9798, 0.2609, 0.3579, 0.9043, 0.5035, "other ..."] }) Item 61: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1347, 0.7000, 0.0530, 0.4959, 0.8227, 0.9831, 0.5433, 0.5201, 0.7924, 0.3847, "other ..."] }) -Item 62: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.2508, 0.5844, 0.0041, 0.8819, 0.9161, 0.9307, 0.1548, 0.3934, 0.6088, 0.6955, "other ..."] }) +Item 62: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7278, 0.0499, 0.4536, 0.3295, 0.8839, 0.5060, 0.5773, 0.3133, 0.2521, 0.6842, "other ..."] }) Item 63: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.9221, 0.3578, 0.3207, 0.9945, 0.9288, 0.4608, 0.3001, 0.0296, 0.4678, 0.7422, "other ..."] }) -Item 64: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5425, 0.6924, 0.4998, 0.1669, 0.2662, 0.0321, 0.0579, 0.4807, 0.8837, 0.6801, "other ..."] }) +Item 64: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.3202, 0.9724, 0.0590, 0.9146, 0.0865, 0.5347, 0.9236, 0.5211, 0.4621, 0.4500, "other ..."] }) Item 65: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5677, 0.1247, 0.4928, 0.4097, 0.8433, 0.9238, 0.7848, 0.4437, 0.4696, 0.9886, "other ..."] }) -Item 66: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7230, 0.6671, 0.4246, 0.9173, 0.8003, 0.2369, 0.6229, 0.1692, 0.5419, 0.5009, "other ..."] }) +Item 66: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7403, 0.1475, 0.8585, 0.3990, 0.5766, 0.0263, 0.2665, 0.6317, 0.8026, 0.0227, "other ..."] }) Item 67: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5299, 0.5421, 0.8194, 0.1018, 0.5426, 0.9350, 0.3228, 0.7979, 0.7473, 0.1118, "other ..."] }) -Item 68: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1253, 0.7856, 0.7688, 0.6142, 0.4916, 0.9840, 0.6736, 0.3734, 0.8886, 0.9260, "other ..."] }) +Item 68: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0981, 0.2398, 0.2595, 0.6075, 0.1605, 0.7487, 0.1070, 0.8330, 0.7908, 0.0203, "other ..."] }) Item 69: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6163, 0.7762, 0.4365, 0.6713, 0.5647, 0.3449, 0.6615, 0.9430, 0.5941, 0.3563, "other ..."] }) -Item 70: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4624, 0.6183, 0.8460, 0.0977, 0.1144, 0.8153, 0.3813, 0.3064, 0.7226, 0.7813, "other ..."] }) +Item 70: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.9586, 0.8715, 0.0659, 0.6144, 0.4995, 0.6693, 0.1415, 0.7556, 0.9350, 0.9924, "other ..."] }) Item 71: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6478, 0.9371, 0.2378, 0.4279, 0.1400, 0.2146, 0.3193, 0.7330, 0.7932, 0.7295, "other ..."] }) -Item 72: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7431, 0.2036, 0.5143, 0.0838, 0.1408, 0.2708, 0.6502, 0.7476, 0.0027, 0.2546, "other ..."] }) +Item 72: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.9907, 0.6582, 0.3640, 0.9777, 0.6001, 0.3023, 0.3154, 0.2637, 0.7202, 0.7507, "other ..."] }) Item 73: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4640, 0.7218, 0.0154, 0.0829, 0.4829, 0.5139, 0.4344, 0.5872, 0.2770, 0.3745, "other ..."] }) -Item 74: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5892, 0.1158, 0.9738, 0.8020, 0.1475, 0.8025, 0.6771, 0.6167, 0.3474, 0.9959, "other ..."] }) +Item 74: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6910, 0.9733, 0.3937, 0.8154, 0.2171, 0.7616, 0.3415, 0.4227, 0.6408, 0.0355, "other ..."] }) Item 75: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.3639, 0.3210, 0.3718, 0.7818, 0.6264, 0.2524, 0.6018, 0.4059, 0.9744, 0.3568, "other ..."] }) -Item 76: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8721, 0.2087, 0.1389, 0.3781, 0.8195, 0.4335, 0.9500, 0.3030, 0.6022, 0.9074, "other ..."] }) +Item 76: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8030, 0.0396, 0.0641, 0.3958, 0.3427, 0.9163, 0.0129, 0.4500, 0.8504, 0.8711, "other ..."] }) Item 77: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6003, 0.7202, 0.3803, 0.5052, 0.4006, 0.6708, 0.0438, 0.8432, 0.8772, 0.6849, "other ..."] }) -Item 78: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1648, 0.5622, 0.8622, 0.4060, 0.9234, 0.4541, 0.7880, 0.6254, 0.6776, 0.7990, "other ..."] }) +Item 78: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6515, 0.6402, 0.4825, 0.1251, 0.1569, 0.9048, 0.3695, 0.0092, 0.1574, 0.1528, "other ..."] }) Item 79: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8093, 0.7442, 0.3738, 0.9164, 0.5923, 0.7353, 0.5379, 0.6815, 0.5925, 0.7954, "other ..."] }) -Item 80: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7110, 0.8746, 0.2891, 0.0877, 0.9762, 0.7313, 0.1369, 0.9363, 0.7791, 0.3066, "other ..."] }) +Item 80: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5256, 0.7737, 0.1071, 0.1049, 0.5131, 0.1703, 0.7922, 0.1135, 0.4165, 0.0898, "other ..."] }) Item 81: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.2370, 0.7334, 0.4755, 0.8921, 0.1448, 0.2971, 0.2116, 0.1124, 0.7297, 0.2965, "other ..."] }) -Item 82: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8911, 0.6624, 0.5524, 0.4579, 0.3863, 0.9061, 0.5681, 0.5999, 0.3466, 0.1909, "other ..."] }) +Item 82: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7826, 0.2989, 0.7770, 0.4571, 0.1601, 0.9667, 0.6717, 0.1903, 0.1169, 0.8590, "other ..."] }) Item 83: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.3071, 0.2166, 0.0566, 0.5153, 0.8628, 0.9601, 0.6390, 0.4052, 0.2759, 0.4989, "other ..."] }) -Item 84: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8972, 0.4273, 0.4040, 0.3423, 0.4314, 0.2713, 0.7759, 0.2579, 0.6453, 0.5287, "other ..."] }) +Item 84: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0498, 0.3107, 0.7264, 0.3119, 0.9096, 0.1574, 0.0399, 0.6895, 0.0600, 0.7256, "other ..."] }) Item 85: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4718, 0.3682, 0.4350, 0.3129, 0.1289, 0.7526, 0.8249, 0.5640, 0.9296, 0.8479, "other ..."] }) -Item 86: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8882, 0.2987, 0.1828, 0.1994, 0.2912, 0.6075, 0.9520, 0.7728, 0.8223, 0.4776, "other ..."] }) +Item 86: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8769, 0.4665, 0.6818, 0.3210, 0.8711, 0.3130, 0.2871, 0.8996, 0.6896, 0.5484, "other ..."] }) Item 87: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.2909, 0.8867, 0.3238, 0.4342, 0.3491, 0.4305, 0.8452, 0.0936, 0.1220, 0.3452, "other ..."] }) -Item 88: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8175, 0.6083, 0.8112, 0.0546, 0.9491, 0.9346, 0.7757, 0.8012, 0.1869, 0.8699, "other ..."] }) +Item 88: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4460, 0.4258, 0.3236, 0.3679, 0.9002, 0.2569, 0.4921, 0.9407, 0.7830, 0.2773, "other ..."] }) Item 89: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6270, 0.3774, 0.7874, 0.7272, 0.4240, 0.1508, 0.0360, 0.5710, 0.2254, 0.0950, "other ..."] }) -Item 90: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1152, 0.5199, 0.9058, 0.4778, 0.0567, 0.4204, 0.6870, 0.5782, 0.8064, 0.4503, "other ..."] }) +Item 90: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.3994, 0.3790, 0.3149, 0.3094, 0.6979, 0.4079, 0.0662, 0.5442, 0.6009, 0.6694, "other ..."] }) Item 91: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8560, 0.9670, 0.3969, 0.5008, 0.1567, 0.7420, 0.0072, 0.1891, 0.9690, 0.0387, "other ..."] }) -Item 92: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1678, 0.5258, 0.9396, 0.9581, 0.4475, 0.2638, 0.5845, 0.7472, 0.5972, 0.2040, "other ..."] }) +Item 92: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1804, 0.0669, 0.8639, 0.6324, 0.8798, 0.3417, 0.1164, 0.5756, 0.9767, 0.7200, "other ..."] }) Item 93: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5034, 0.4728, 0.9950, 0.7630, 0.0154, 0.4453, 0.6893, 0.6996, 0.0246, 0.0245, "other ..."] }) -Item 94: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.6528, 0.1518, 0.1914, 0.6531, 0.1864, 0.8516, 0.8513, 0.7597, 0.7184, 0.9471, "other ..."] }) +Item 94: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1112, 0.3992, 0.0741, 0.7318, 0.9446, 0.2970, 0.9245, 0.1696, 0.6283, 0.9061, "other ..."] }) Item 95: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8157, 0.8688, 0.2659, 0.6080, 0.5274, 0.1883, 0.7562, 0.8511, 0.6928, 0.8151, "other ..."] }) -Item 96: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8466, 0.5695, 0.6938, 0.2837, 0.1516, 0.5060, 0.6954, 0.6374, 0.2537, 0.2103, "other ..."] }) +Item 96: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.5324, 0.0597, 0.9226, 0.4007, 0.0213, 0.2651, 0.8515, 0.9985, 0.8066, 0.3377, "other ..."] }) Item 97: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0850, 0.4087, 0.7257, 0.3157, 0.9526, 0.5290, 0.5818, 0.5460, 0.1906, 0.9422, "other ..."] }) -Item 98: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.7869, 0.7930, 0.1927, 0.3278, 0.9169, 0.1851, 0.6830, 0.8456, 0.3333, 0.4058, "other ..."] }) +Item 98: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8413, 0.5136, 0.9661, 0.4242, 0.3183, 0.6281, 0.1580, 0.7145, 0.7564, 0.3747, "other ..."] }) Item 99: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8320, 0.5156, 0.6172, 0.6617, 0.4999, 0.2464, 0.4536, 0.3265, 0.2163, 0.5406, "other ..."] }) diff --git a/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points.snap b/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points.snap index e81c751..b6b894d 100644 --- a/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points.snap +++ b/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points.snap @@ -6,104 +6,98 @@ expression: handle Dumping index 0 Root: Metadata { dimensions: 30, items: RoaringBitmap<100 values between 0 and 99>, roots: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } -Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 92, right: 97, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3716" }, vector: [0.1332, -0.0086, -0.0332, 0.3903, -0.1149, 0.0165, 0.0177, -0.2272, -0.0616, -0.0471, "other ..."] } }) -Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 82, right: 87, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3513" }, vector: [-0.1907, 0.0249, 0.0882, 0.0445, 0.0329, 0.2224, -0.0366, -0.3159, -0.1131, 0.1267, "other ..."] } }) -Tree 2: SplitPlaneNormal(SplitPlaneNormal { left: 72, right: 79, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.4519" }, vector: [0.1173, 0.3077, 0.0145, 0.0027, -0.3801, 0.1215, -0.1959, -0.1847, -0.1231, 0.0874, "other ..."] } }) -Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 62, right: 69, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.5850" }, vector: [0.0380, 0.1603, -0.3896, -0.1186, 0.0911, -0.0967, -0.0213, 0.2811, -0.3599, -0.4255, "other ..."] } }) -Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 56, right: 59, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0456" }, vector: [-0.1512, 0.1699, 0.2254, -0.2646, -0.2503, 0.2765, -0.1126, -0.0710, -0.0636, -0.0934, "other ..."] } }) -Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 44, right: 51, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.6517" }, vector: [-0.1426, 0.1041, -0.0253, 0.2489, 0.0095, -0.0057, 0.0741, -0.0359, -0.1958, 0.2323, "other ..."] } }) -Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 38, right: 41, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.2643" }, vector: [0.1950, -0.3941, -0.2712, 0.0233, 0.1903, 0.4587, -0.1344, -0.0574, -0.0227, -0.2019, "other ..."] } }) -Tree 7: SplitPlaneNormal(SplitPlaneNormal { left: 30, right: 33, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0533" }, vector: [0.0260, 0.0441, -0.0001, 0.1366, 0.2223, 0.0095, 0.0044, 0.2319, -0.2957, -0.0180, "other ..."] } }) -Tree 8: SplitPlaneNormal(SplitPlaneNormal { left: 22, right: 25, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3110" }, vector: [-0.0130, 0.0421, 0.0374, -0.3224, -0.2745, 0.0954, 0.1471, -0.0139, 0.1443, 0.3814, "other ..."] } }) -Tree 9: SplitPlaneNormal(SplitPlaneNormal { left: 14, right: 17, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0740" }, vector: [-0.1374, 0.0838, -0.0510, 0.1656, -0.1541, -0.1150, -0.2054, -0.4952, -0.3053, -0.0348, "other ..."] } }) -Tree 10: Descendants(Descendants { descendants: [16, 21, 22, 41, 43, 46, 59, 60, 66, 67, 72, 73, 78, 80, 81, 83] }) -Tree 11: Descendants(Descendants { descendants: [0, 2, 7, 9, 11, 23, 29, 35, 44, 74, 77, 86, 89, 95, 96, 97, 98, 99] }) -Tree 12: Descendants(Descendants { descendants: [3, 4, 12, 15, 17, 18, 37, 38, 39, 47, 53, 55, 58, 64, 65, 69, 71, 75, 76, 79, 82, 85, 88, 94] }) -Tree 13: SplitPlaneNormal(SplitPlaneNormal { left: 11, right: 12, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.8991" }, vector: [-0.1758, 0.1024, 0.1705, -0.2147, 0.0264, 0.0784, 0.3732, 0.0459, 0.2562, 0.0502, "other ..."] } }) -Tree 14: SplitPlaneNormal(SplitPlaneNormal { left: 10, right: 13, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.2300" }, vector: [-0.0720, -0.0814, 0.0454, -0.0944, -0.0123, -0.2516, 0.1854, 0.3585, 0.1772, 0.3414, "other ..."] } }) -Tree 15: Descendants(Descendants { descendants: [1, 5, 6, 14, 25, 26, 30, 31, 34, 40, 42, 48, 49, 62, 91, 92, 93] }) -Tree 16: Descendants(Descendants { descendants: [8, 10, 13, 19, 20, 24, 27, 28, 32, 33, 36, 45, 50, 51, 52, 54, 56, 57, 61, 63, 68, 70, 84, 87, 90] }) -Tree 17: SplitPlaneNormal(SplitPlaneNormal { left: 15, right: 16, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.4707" }, vector: [-0.1805, 0.0550, -0.1537, -0.0484, 0.2185, -0.3491, 0.1785, -0.0136, -0.0352, 0.2647, "other ..."] } }) -Tree 18: Descendants(Descendants { descendants: [0, 1, 26, 28, 31, 35, 36, 39, 45, 48, 50, 51, 70, 76, 80, 81, 89, 90, 93, 96, 97] }) -Tree 19: Descendants(Descendants { descendants: [3, 16, 29, 38, 43, 54, 57, 58, 63, 65, 83, 95] }) -Tree 20: SplitPlaneNormal(SplitPlaneNormal { left: 18, right: 19, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.2996" }, vector: [0.0162, 0.0407, -0.0344, -0.2744, 0.1377, 0.1689, 0.1236, -0.0230, 0.3440, 0.3553, "other ..."] } }) -Tree 21: Descendants(Descendants { descendants: [10, 13, 14, 19, 20, 21, 32, 34, 41, 42, 44, 62, 69, 84, 86, 91] }) -Tree 22: SplitPlaneNormal(SplitPlaneNormal { left: 20, right: 21, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.5274" }, vector: [-0.0635, 0.1294, -0.0848, 0.1272, -0.0340, 0.0735, -0.2067, 0.1933, 0.2726, -0.2752, "other ..."] } }) -Tree 23: Descendants(Descendants { descendants: [4, 8, 11, 18, 22, 23, 30, 37, 52, 53, 55, 56, 64, 66, 67, 68, 71, 72, 73, 74, 75, 78, 98] }) -Tree 24: Descendants(Descendants { descendants: [2, 5, 6, 7, 9, 12, 15, 17, 24, 25, 27, 33, 40, 46, 47, 49, 59, 60, 61, 77, 79, 82, 85, 87, 88, 92, 94, 99] }) -Tree 25: SplitPlaneNormal(SplitPlaneNormal { left: 23, right: 24, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0115" }, vector: [-0.1825, -0.1677, 0.1141, 0.2436, -0.0449, 0.1842, 0.0754, -0.0677, -0.1810, 0.3995, "other ..."] } }) -Tree 26: Descendants(Descendants { descendants: [16, 18, 20, 26, 32, 41, 43, 49, 53, 59, 74, 82, 84, 88, 99] }) -Tree 27: Descendants(Descendants { descendants: [5, 12, 14, 15, 17, 22, 23, 38, 55, 58, 60, 61, 68, 69, 71, 75, 77, 79, 80, 81, 83, 94] }) -Tree 28: SplitPlaneNormal(SplitPlaneNormal { left: 26, right: 27, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0205" }, vector: [-0.1341, 0.1901, 0.0261, -0.0438, -0.0936, -0.0997, 0.1599, 0.2235, -0.1590, 0.3721, "other ..."] } }) -Tree 29: Descendants(Descendants { descendants: [9, 11, 19, 24, 25, 30, 31, 33, 34, 35, 40, 42, 46, 52, 56, 64, 72, 78, 85, 86, 87, 91, 92, 98] }) -Tree 30: SplitPlaneNormal(SplitPlaneNormal { left: 28, right: 29, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.4032" }, vector: [-0.0548, -0.0095, -0.0118, 0.0441, 0.1735, 0.2693, -0.0440, -0.1215, -0.0498, -0.1885, "other ..."] } }) -Tree 31: Descendants(Descendants { descendants: [0, 2, 4, 7, 29, 37, 39, 44, 47, 50, 62, 65, 67, 70, 76, 93, 96, 97] }) -Tree 32: Descendants(Descendants { descendants: [1, 3, 6, 8, 10, 13, 21, 27, 28, 36, 45, 48, 51, 54, 57, 63, 66, 73, 89, 90, 95] }) -Tree 33: SplitPlaneNormal(SplitPlaneNormal { left: 31, right: 32, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.7503" }, vector: [0.0460, -0.0698, -0.2186, 0.1742, -0.1312, -0.2232, -0.1783, -0.4384, 0.0899, -0.0048, "other ..."] } }) -Tree 34: Descendants(Descendants { descendants: [7, 8, 21, 23, 37, 43, 47, 55, 57, 66, 68, 72, 73, 77, 78, 80, 81, 85, 86, 89, 95] }) -Tree 35: Descendants(Descendants { descendants: [3, 6, 16, 22, 27, 28, 45, 50, 54, 67, 90, 91, 96, 97] }) -Tree 36: SplitPlaneNormal(SplitPlaneNormal { left: 34, right: 35, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3682" }, vector: [0.1124, -0.0747, 0.2287, 0.1726, 0.2342, 0.1426, -0.0741, 0.1171, -0.1589, -0.0065, "other ..."] } }) -Tree 37: Descendants(Descendants { descendants: [1, 2, 5, 12, 14, 15, 17, 26, 62, 69, 71, 79, 87, 88, 94, 98, 99] }) -Tree 38: SplitPlaneNormal(SplitPlaneNormal { left: 36, right: 37, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.5351" }, vector: [-0.0064, -0.1766, 0.2360, 0.1083, -0.1097, 0.0400, 0.1768, 0.1568, 0.0968, 0.0100, "other ..."] } }) -Tree 39: Descendants(Descendants { descendants: [0, 4, 9, 11, 18, 19, 25, 29, 30, 35, 40, 41, 42, 44, 46, 49, 51, 52, 53, 56, 60, 64, 74, 75, 76] }) -Tree 40: Descendants(Descendants { descendants: [10, 13, 20, 24, 31, 32, 33, 34, 36, 38, 39, 48, 58, 59, 61, 63, 65, 70, 82, 83, 84, 92, 93] }) -Tree 41: SplitPlaneNormal(SplitPlaneNormal { left: 39, right: 40, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.1828" }, vector: [-0.0943, -0.0695, 0.2540, -0.0578, -0.1686, -0.1354, 0.0186, -0.3112, -0.1013, 0.2727, "other ..."] } }) -Tree 42: Descendants(Descendants { descendants: [0, 8, 15, 28, 37, 40, 48, 52, 54, 60, 71, 73, 75, 77, 87] }) -Tree 43: Descendants(Descendants { descendants: [5, 16, 19, 22, 23, 27, 42, 45, 46, 59, 64, 67, 72, 78, 91, 98] }) -Tree 44: SplitPlaneNormal(SplitPlaneNormal { left: 42, right: 43, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.4745" }, vector: [-0.1090, 0.2068, 0.1310, -0.1556, 0.1981, 0.2558, -0.2902, -0.1297, 0.0405, -0.0000, "other ..."] } }) -Tree 45: Descendants(Descendants { descendants: [10, 13, 25, 30, 36, 39, 56, 62, 66, 85, 93] }) -Tree 46: Descendants(Descendants { descendants: [3, 6, 7, 14, 17, 20, 21, 26, 41, 47, 55, 68, 70, 79, 81, 86, 90, 95, 96] }) -Tree 47: Descendants(Descendants { descendants: [4, 9, 11, 18, 24, 32, 33, 38, 49, 53, 57, 58, 61, 65, 69, 74, 76, 83, 84, 88, 94, 97] }) -Tree 48: SplitPlaneNormal(SplitPlaneNormal { left: 46, right: 47, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.7605" }, vector: [-0.1718, -0.1744, 0.1322, -0.0418, 0.2455, 0.1712, 0.3536, 0.1988, -0.2401, 0.0592, "other ..."] } }) -Tree 49: Descendants(Descendants { descendants: [1, 2, 12, 29, 31, 34, 35, 43, 44, 50, 51, 63, 80, 82, 89, 92, 99] }) -Tree 50: SplitPlaneNormal(SplitPlaneNormal { left: 48, right: 49, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0260" }, vector: [0.2283, -0.1252, 0.1602, -0.0038, 0.0129, -0.2951, -0.2565, -0.1041, -0.2764, -0.1719, "other ..."] } }) -Tree 51: SplitPlaneNormal(SplitPlaneNormal { left: 45, right: 50, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.6595" }, vector: [-0.0635, -0.2061, -0.0851, 0.1272, 0.0083, -0.2721, 0.1119, 0.2789, 0.2137, 0.1339, "other ..."] } }) -Tree 52: Descendants(Descendants { descendants: [8, 15, 37, 57, 61, 77, 83, 87, 90, 95] }) -Tree 53: Descendants(Descendants { descendants: [0, 4, 7, 9, 13, 27, 28, 31, 35, 38, 39, 45, 48, 50, 51, 53, 55, 58, 60, 63, 64, 69, 70, 75, 94, 96, 97, 99] }) -Tree 54: SplitPlaneNormal(SplitPlaneNormal { left: 52, right: 53, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.1107" }, vector: [-0.0284, -0.0542, 0.0370, 0.0608, 0.2432, 0.2367, 0.1349, -0.2057, -0.2642, -0.1627, "other ..."] } }) -Tree 55: Descendants(Descendants { descendants: [3, 6, 12, 17, 19, 21, 23, 40, 41, 42, 52, 68, 71, 78, 79, 80, 81, 86, 98] }) -Tree 56: SplitPlaneNormal(SplitPlaneNormal { left: 54, right: 55, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3720" }, vector: [0.0401, 0.3800, 0.2200, 0.1918, -0.1184, -0.1624, -0.3477, 0.0335, 0.3667, -0.0673, "other ..."] } }) -Tree 57: Descendants(Descendants { descendants: [16, 18, 20, 22, 24, 36, 43, 46, 47, 54, 56, 59, 66, 72, 73, 76, 85, 89, 93] }) -Tree 58: Descendants(Descendants { descendants: [1, 2, 5, 10, 11, 14, 25, 26, 29, 30, 32, 33, 34, 44, 49, 62, 65, 67, 74, 82, 84, 88, 91, 92] }) -Tree 59: SplitPlaneNormal(SplitPlaneNormal { left: 57, right: 58, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3047" }, vector: [-0.1732, -0.2471, -0.0571, -0.0385, -0.1814, 0.1221, -0.1369, -0.0452, 0.1554, -0.0974, "other ..."] } }) -Tree 60: Descendants(Descendants { descendants: [5, 6, 15, 16, 32, 33, 42, 49, 59, 63, 79, 82, 84, 88, 94] }) -Tree 61: Descendants(Descendants { descendants: [3, 17, 25, 26, 27, 36, 40, 55, 57, 60, 62, 65, 77, 85, 90, 97] }) -Tree 62: SplitPlaneNormal(SplitPlaneNormal { left: 60, right: 61, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3698" }, vector: [-0.2559, 0.0491, -0.3892, -0.1506, -0.2084, 0.0986, 0.0673, -0.1076, 0.0829, 0.0353, "other ..."] } }) -Tree 63: Descendants(Descendants { descendants: [21, 22, 37, 93, 96] }) -Tree 64: Descendants(Descendants { descendants: [0, 2, 4, 7, 9, 11, 14, 18, 29, 30, 31, 39, 45, 48, 50, 51, 56, 66, 67, 70, 72, 74, 80, 81, 86, 89, 91, 95] }) -Tree 65: SplitPlaneNormal(SplitPlaneNormal { left: 63, right: 64, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3553" }, vector: [-0.0946, -0.0869, -0.1250, -0.0772, 0.0995, 0.0790, -0.1889, -0.2008, -0.0048, 0.0248, "other ..."] } }) -Tree 66: Descendants(Descendants { descendants: [12, 20, 23, 24, 34, 38, 43, 44, 47, 58, 61, 71, 76, 83] }) -Tree 67: Descendants(Descendants { descendants: [1, 8, 10, 13, 19, 28, 35, 41, 46, 52, 53, 54, 64, 68, 69, 73, 75, 78, 87, 92, 98, 99] }) -Tree 68: SplitPlaneNormal(SplitPlaneNormal { left: 66, right: 67, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.2903" }, vector: [0.0272, 0.0294, -0.0549, 0.0864, 0.1612, -0.2692, 0.0908, -0.1628, 0.2455, -0.1355, "other ..."] } }) -Tree 69: SplitPlaneNormal(SplitPlaneNormal { left: 65, right: 68, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3590" }, vector: [-0.0595, -0.0724, -0.5327, 0.1397, 0.1090, -0.0954, 0.0156, -0.2676, 0.1233, 0.2413, "other ..."] } }) -Tree 70: Descendants(Descendants { descendants: [1, 4, 10, 11, 14, 19, 27, 29, 31, 35, 37, 41, 45, 48, 64, 65, 69, 70, 75, 84, 85, 91, 97, 98] }) -Tree 71: Descendants(Descendants { descendants: [0, 3, 9, 18, 39, 42, 50, 62, 96] }) -Tree 72: SplitPlaneNormal(SplitPlaneNormal { left: 70, right: 71, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.4930" }, vector: [-0.1326, 0.1931, 0.3305, 0.1302, -0.0262, -0.3077, -0.0631, 0.1835, 0.2803, 0.0471, "other ..."] } }) -Tree 73: Descendants(Descendants { descendants: [2, 5, 7, 12, 15, 17, 23, 38, 40, 43, 53, 55, 59, 74, 77, 80, 82, 87, 88, 89, 92, 93, 99] }) -Tree 74: Descendants(Descendants { descendants: [6, 8, 20, 21, 26, 28, 47, 52, 54, 57, 58, 61, 63, 68, 71, 73, 78, 79, 81, 86, 90, 95] }) -Tree 75: Descendants(Descendants { descendants: [16, 22, 24, 25, 32, 33, 34, 44, 49, 60, 67, 76, 83, 94] }) -Tree 76: SplitPlaneNormal(SplitPlaneNormal { left: 74, right: 75, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.1553" }, vector: [-0.0141, -0.3762, 0.1482, 0.2402, -0.0572, 0.3452, -0.0756, -0.0084, -0.2257, -0.3384, "other ..."] } }) -Tree 77: Descendants(Descendants { descendants: [13, 30, 36, 46, 51, 56, 66, 72] }) -Tree 78: SplitPlaneNormal(SplitPlaneNormal { left: 76, right: 77, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.7287" }, vector: [0.0663, 0.1811, 0.3964, 0.0248, 0.1054, 0.0248, -0.2118, -0.3715, -0.1975, -0.1672, "other ..."] } }) -Tree 79: SplitPlaneNormal(SplitPlaneNormal { left: 73, right: 78, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0254" }, vector: [0.1396, 0.0343, -0.3978, 0.3344, 0.0795, 0.2614, 0.0287, -0.2709, 0.1147, -0.1712, "other ..."] } }) -Tree 80: Descendants(Descendants { descendants: [8, 12, 21, 23, 35, 37, 41, 43, 47, 49, 51, 53, 55, 56, 58, 59, 60, 61, 64, 68, 71, 74, 78, 80, 81, 82, 92, 95] }) -Tree 81: Descendants(Descendants { descendants: [0, 4, 7, 9, 14, 15, 17, 18, 20, 22, 31, 32, 34, 38, 52, 69, 75, 79, 84, 86, 88, 94, 99] }) -Tree 82: SplitPlaneNormal(SplitPlaneNormal { left: 80, right: 81, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.5162" }, vector: [0.0672, 0.0920, 0.4100, 0.1060, -0.0216, 0.2297, -0.1265, 0.1477, -0.1835, 0.1038, "other ..."] } }) -Tree 83: Descendants(Descendants { descendants: [1, 10, 36, 42, 62, 76, 89, 93] }) -Tree 84: Descendants(Descendants { descendants: [2, 3, 5, 19, 24, 25, 26, 27, 30, 33, 39, 40, 44, 46, 57, 65, 66, 70, 72, 77, 85, 90, 97, 98] }) -Tree 85: SplitPlaneNormal(SplitPlaneNormal { left: 83, right: 84, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.2657" }, vector: [-0.1633, 0.0793, -0.1072, -0.3704, 0.1666, 0.1013, 0.1114, 0.1223, 0.4362, 0.2133, "other ..."] } }) -Tree 86: Descendants(Descendants { descendants: [6, 11, 13, 16, 28, 29, 45, 48, 50, 54, 63, 67, 73, 83, 87, 91, 96] }) -Tree 87: SplitPlaneNormal(SplitPlaneNormal { left: 85, right: 86, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.6931" }, vector: [0.3818, -0.0721, -0.2808, 0.0421, 0.0616, -0.2107, -0.1180, -0.1258, -0.2356, -0.2022, "other ..."] } }) -Tree 88: Descendants(Descendants { descendants: [3, 5, 7, 12, 15, 19, 24, 27, 30, 39, 52, 67, 69, 72, 73, 80, 83, 87, 98] }) -Tree 89: Descendants(Descendants { descendants: [2, 4, 8, 10, 11, 28, 29, 37, 46, 55, 57, 66, 94, 97, 99] }) -Tree 90: SplitPlaneNormal(SplitPlaneNormal { left: 88, right: 89, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.1856" }, vector: [0.1610, -0.3179, -0.1850, 0.0541, 0.3918, -0.1846, 0.1157, -0.0056, -0.2183, -0.1200, "other ..."] } }) -Tree 91: Descendants(Descendants { descendants: [17, 18, 23, 25, 40, 47, 53, 56, 60, 61, 64, 68, 71, 74, 78, 85] }) -Tree 92: SplitPlaneNormal(SplitPlaneNormal { left: 90, right: 91, normal: Leaf { header: NodeHeaderEuclidean { bias: "-1.1208" }, vector: [-0.1025, 0.0479, -0.1978, 0.0985, -0.3313, 0.2821, 0.1609, 0.1877, 0.4123, 0.2166, "other ..."] } }) -Tree 93: Descendants(Descendants { descendants: [0, 14, 31, 42, 48, 50, 70, 81, 86, 95] }) -Tree 94: Descendants(Descendants { descendants: [9, 20, 26, 32, 33, 34, 35, 36, 38, 44, 49, 51, 58, 59, 65, 75, 76, 82, 84, 88, 89, 92] }) -Tree 95: SplitPlaneNormal(SplitPlaneNormal { left: 93, right: 94, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.4296" }, vector: [-0.1762, -0.1044, 0.3316, 0.1360, 0.0818, 0.1789, -0.0195, 0.0589, -0.1702, 0.0343, "other ..."] } }) -Tree 96: Descendants(Descendants { descendants: [1, 6, 13, 16, 21, 22, 41, 43, 45, 54, 62, 63, 77, 79, 90, 91, 93, 96] }) -Tree 97: SplitPlaneNormal(SplitPlaneNormal { left: 95, right: 96, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0570" }, vector: [0.0800, 0.3656, -0.0449, -0.1135, -0.1656, 0.1626, 0.0858, -0.1268, -0.1497, 0.0165, "other ..."] } }) +Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 88, right: 91, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3733" }, vector: [-0.0475, -0.1496, 0.1344, -0.1902, -0.2161, -0.4158, -0.1593, 0.1212, -0.0136, 0.2277, "other ..."] } }) +Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 76, right: 81, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.4143" }, vector: [-0.1850, 0.1162, 0.1506, 0.1488, 0.2308, 0.1370, -0.2152, -0.0274, -0.0407, -0.2282, "other ..."] } }) +Tree 2: SplitPlaneNormal(SplitPlaneNormal { left: 66, right: 73, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0804" }, vector: [0.1941, -0.1680, -0.0860, -0.4588, 0.2054, 0.0884, 0.0622, 0.1314, 0.1377, -0.2936, "other ..."] } }) +Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 58, right: 63, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0458" }, vector: [-0.0598, -0.0926, -0.1871, -0.0077, 0.2839, 0.2008, 0.1168, -0.3345, -0.0870, 0.0621, "other ..."] } }) +Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 50, right: 53, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0933" }, vector: [-0.2249, -0.2354, -0.2492, 0.0508, -0.0488, 0.3083, 0.0932, -0.0190, -0.4116, -0.0404, "other ..."] } }) +Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 38, right: 45, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0963" }, vector: [0.0636, -0.2729, 0.4830, 0.1626, 0.0343, -0.0273, -0.0742, 0.0450, -0.3975, -0.3293, "other ..."] } }) +Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 32, right: 35, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.6869" }, vector: [0.0755, 0.2682, -0.0986, 0.3341, 0.0086, -0.0666, -0.2590, -0.1551, 0.0651, -0.0362, "other ..."] } }) +Tree 7: SplitPlaneNormal(SplitPlaneNormal { left: 26, right: 29, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0797" }, vector: [-0.0053, 0.4627, 0.0033, -0.1321, 0.2763, -0.0670, -0.0985, -0.1405, 0.3819, 0.0681, "other ..."] } }) +Tree 8: SplitPlaneNormal(SplitPlaneNormal { left: 22, right: 23, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3843" }, vector: [-0.3055, 0.2263, 0.3598, -0.0777, -0.0538, -0.1513, -0.0809, 0.1401, 0.0514, 0.2712, "other ..."] } }) +Tree 9: SplitPlaneNormal(SplitPlaneNormal { left: 12, right: 17, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.9466" }, vector: [-0.1459, -0.2139, -0.2989, 0.0100, -0.1856, -0.0497, 0.1403, 0.0371, -0.2027, 0.1831, "other ..."] } }) +Tree 10: Descendants(Descendants { descendants: [2, 11, 13, 19, 20, 24, 30, 36, 39, 41, 42, 43, 45, 46, 51, 54, 56, 59, 62, 66, 68, 77, 80, 85, 89, 91, 92, 93] }) +Tree 11: Descendants(Descendants { descendants: [4, 8, 18, 21, 22, 52, 64, 67, 72, 78, 98] }) +Tree 12: SplitPlaneNormal(SplitPlaneNormal { left: 10, right: 11, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.1444" }, vector: [0.0412, 0.0950, -0.0460, -0.3947, -0.0556, 0.1065, 0.1877, 0.3147, 0.2321, -0.1957, "other ..."] } }) +Tree 13: Descendants(Descendants { descendants: [3, 14, 17, 25, 26, 32, 33, 37, 38, 44, 47, 50, 55, 57, 61, 71, 73, 79, 88, 90, 94, 95, 96] }) +Tree 14: Descendants(Descendants { descendants: [6, 12, 15, 23, 27, 28, 34, 40, 81, 86, 87, 99] }) +Tree 15: SplitPlaneNormal(SplitPlaneNormal { left: 13, right: 14, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3565" }, vector: [0.1751, -0.0027, -0.1028, -0.0282, 0.0387, -0.1329, -0.1364, -0.2423, -0.1042, -0.1441, "other ..."] } }) +Tree 16: Descendants(Descendants { descendants: [0, 1, 5, 7, 9, 10, 16, 29, 31, 35, 48, 49, 53, 58, 60, 63, 65, 69, 70, 74, 75, 76, 82, 83, 84, 97] }) +Tree 17: SplitPlaneNormal(SplitPlaneNormal { left: 15, right: 16, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3772" }, vector: [0.1033, -0.4242, -0.0800, -0.1632, 0.1052, -0.0050, 0.2207, -0.1568, -0.0534, -0.0278, "other ..."] } }) +Tree 18: Descendants(Descendants { descendants: [12, 16, 20, 21, 22, 23, 31, 34, 35, 43, 45, 47, 48, 49, 50, 51, 54, 58, 59, 61, 64, 68, 71, 75, 76, 78, 87, 89, 90, 94] }) +Tree 19: Descendants(Descendants { descendants: [10, 13, 19, 24, 30, 33, 36, 44, 46, 56, 63, 65, 72, 80, 83, 92] }) +Tree 20: SplitPlaneNormal(SplitPlaneNormal { left: 18, right: 19, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.6890" }, vector: [-0.0953, 0.0544, -0.0235, -0.3023, 0.1023, 0.4182, -0.2031, -0.1618, -0.1613, 0.2265, "other ..."] } }) +Tree 21: Descendants(Descendants { descendants: [0, 4, 6, 8, 11, 25, 28, 29, 32, 37, 40, 41, 42, 52, 55, 57, 60, 67, 70, 74, 77, 85, 86, 91, 93, 95, 97, 98, 99] }) +Tree 22: SplitPlaneNormal(SplitPlaneNormal { left: 20, right: 21, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.2139" }, vector: [0.0683, -0.0814, 0.0252, -0.1067, -0.2097, -0.0424, 0.1001, 0.3194, 0.0825, 0.0236, "other ..."] } }) +Tree 23: Descendants(Descendants { descendants: [1, 2, 3, 5, 7, 9, 14, 15, 17, 18, 26, 27, 38, 39, 53, 62, 66, 69, 73, 79, 81, 82, 84, 88, 96] }) +Tree 24: Descendants(Descendants { descendants: [4, 5, 12, 15, 18, 22, 29, 31, 33, 38, 49, 50, 56, 58, 59, 62, 65, 69, 74, 76, 82, 84, 88, 93, 94] }) +Tree 25: Descendants(Descendants { descendants: [0, 1, 7, 10, 11, 20, 24, 25, 30, 32, 34, 35, 36, 44, 48, 60, 63, 70, 83, 89, 92] }) +Tree 26: SplitPlaneNormal(SplitPlaneNormal { left: 24, right: 25, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.8580" }, vector: [0.0064, -0.0347, -0.5050, 0.1150, -0.1841, -0.1740, -0.1482, -0.2880, 0.0158, -0.1222, "other ..."] } }) +Tree 27: Descendants(Descendants { descendants: [2, 6, 16, 17, 19, 23, 26, 27, 28, 40, 41, 42, 45, 47, 53, 55, 64, 68, 71, 73, 77, 79, 91, 97, 99] }) +Tree 28: Descendants(Descendants { descendants: [3, 8, 9, 13, 14, 21, 37, 39, 43, 46, 51, 52, 54, 57, 61, 66, 67, 72, 75, 78, 80, 81, 85, 86, 87, 90, 95, 96, 98] }) +Tree 29: SplitPlaneNormal(SplitPlaneNormal { left: 27, right: 28, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3445" }, vector: [0.0543, -0.0671, 0.0759, 0.0437, -0.0054, -0.0953, 0.1007, 0.0988, 0.0009, -0.2796, "other ..."] } }) +Tree 30: Descendants(Descendants { descendants: [5, 9, 12, 15, 17, 18, 22, 33, 52, 53, 58, 69, 71, 74, 75, 82, 85, 88, 99] }) +Tree 31: Descendants(Descendants { descendants: [4, 10, 25, 29, 30, 31, 32, 34, 35, 38, 39, 41, 43, 49, 51, 59, 60, 64, 65, 70, 76, 83, 84, 92] }) +Tree 32: SplitPlaneNormal(SplitPlaneNormal { left: 30, right: 31, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0413" }, vector: [-0.1386, -0.0892, -0.2192, 0.1007, 0.1662, 0.1992, 0.1561, -0.1894, -0.0047, -0.5036, "other ..."] } }) +Tree 33: Descendants(Descendants { descendants: [0, 2, 3, 7, 16, 21, 23, 24, 37, 44, 47, 50, 55, 57, 66, 67, 68, 73, 77, 80, 81, 87, 89, 94, 95, 96, 97, 98] }) +Tree 34: Descendants(Descendants { descendants: [1, 6, 8, 11, 13, 14, 19, 20, 26, 27, 28, 36, 40, 42, 45, 46, 48, 54, 56, 61, 62, 63, 72, 78, 79, 86, 90, 91, 93] }) +Tree 35: SplitPlaneNormal(SplitPlaneNormal { left: 33, right: 34, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.7813" }, vector: [0.2283, -0.0301, 0.0221, 0.3419, -0.1074, 0.1028, -0.0143, -0.4095, 0.1713, -0.2207, "other ..."] } }) +Tree 36: Descendants(Descendants { descendants: [18, 23, 24, 38, 41, 43, 47, 61, 64, 71, 79, 95] }) +Tree 37: Descendants(Descendants { descendants: [3, 6, 8, 17, 19, 20, 21, 26, 27, 37, 46, 52, 53, 55, 57, 60, 66, 68, 72, 73, 77, 78, 81, 85, 86, 87, 90, 91] }) +Tree 38: SplitPlaneNormal(SplitPlaneNormal { left: 36, right: 37, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.9826" }, vector: [0.0621, 0.1333, 0.1151, -0.1787, -0.1980, -0.2909, -0.1670, -0.2455, 0.1465, -0.2411, "other ..."] } }) +Tree 39: Descendants(Descendants { descendants: [9, 30, 33, 65] }) +Tree 40: Descendants(Descendants { descendants: [1, 13, 15, 16, 22, 28, 36, 45, 48, 54, 56, 58, 63, 80, 83, 89, 94, 97] }) +Tree 41: Descendants(Descendants { descendants: [0, 2, 7, 11, 14, 39, 40, 42, 44, 62, 67, 69, 96, 98, 99] }) +Tree 42: SplitPlaneNormal(SplitPlaneNormal { left: 40, right: 41, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3337" }, vector: [-0.0277, 0.0111, 0.2902, -0.1474, -0.2389, 0.1891, -0.1465, 0.3082, 0.3863, -0.1365, "other ..."] } }) +Tree 43: SplitPlaneNormal(SplitPlaneNormal { left: 39, right: 42, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.7534" }, vector: [-0.0250, -0.2548, 0.1022, 0.2544, -0.2040, -0.3794, -0.0195, 0.2224, -0.0019, -0.2172, "other ..."] } }) +Tree 44: Descendants(Descendants { descendants: [4, 5, 10, 12, 25, 29, 31, 32, 34, 35, 49, 50, 51, 59, 70, 74, 75, 76, 82, 84, 88, 92, 93] }) +Tree 45: SplitPlaneNormal(SplitPlaneNormal { left: 43, right: 44, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0741" }, vector: [-0.1841, -0.3075, -0.1588, -0.0624, -0.0917, -0.1359, 0.3864, -0.1105, -0.0036, -0.2592, "other ..."] } }) +Tree 46: Descendants(Descendants { descendants: [0, 4, 11, 14, 15, 17, 18, 20, 32, 35, 49, 52, 53, 55, 56, 59, 75, 77, 84, 89, 92, 94, 98] }) +Tree 47: Descendants(Descendants { descendants: [3, 24, 30, 39, 46, 62, 66, 67, 69, 73, 91] }) +Tree 48: SplitPlaneNormal(SplitPlaneNormal { left: 46, right: 47, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0823" }, vector: [-0.0437, 0.4360, 0.0071, -0.3022, 0.1217, 0.0621, -0.0552, -0.1529, -0.1505, 0.1638, "other ..."] } }) +Tree 49: Descendants(Descendants { descendants: [6, 8, 16, 19, 21, 22, 23, 28, 37, 43, 54, 58, 60, 63, 64, 68, 71, 72, 78, 79, 80, 82, 88, 90, 99] }) +Tree 50: SplitPlaneNormal(SplitPlaneNormal { left: 48, right: 49, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0810" }, vector: [0.0085, 0.1364, -0.1779, 0.1409, 0.0822, -0.1502, 0.2116, -0.3355, 0.1380, 0.0108, "other ..."] } }) +Tree 51: Descendants(Descendants { descendants: [2, 7, 12, 27, 29, 33, 34, 36, 47, 51, 57, 61, 74, 85, 86, 93, 95, 96, 97] }) +Tree 52: Descendants(Descendants { descendants: [1, 5, 9, 10, 13, 25, 26, 31, 38, 40, 41, 42, 44, 45, 48, 50, 65, 70, 76, 81, 83, 87] }) +Tree 53: SplitPlaneNormal(SplitPlaneNormal { left: 51, right: 52, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.1338" }, vector: [-0.0609, 0.0086, -0.2000, 0.0923, 0.1533, 0.1656, -0.0856, -0.3540, 0.1304, -0.0072, "other ..."] } }) +Tree 54: Descendants(Descendants { descendants: [36, 39, 62, 81, 89, 93] }) +Tree 55: Descendants(Descendants { descendants: [0, 1, 3, 6, 9, 14, 26, 29, 32, 34, 37, 38, 44, 47, 50, 54, 57, 61, 74, 77, 79, 86, 90, 95, 96] }) +Tree 56: SplitPlaneNormal(SplitPlaneNormal { left: 54, right: 55, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.7111" }, vector: [-0.0483, 0.0173, -0.3836, -0.1830, 0.2282, 0.0862, 0.0591, 0.2533, -0.0096, 0.1085, "other ..."] } }) +Tree 57: Descendants(Descendants { descendants: [15, 20, 21, 22, 43, 58, 71, 76, 80, 82] }) +Tree 58: SplitPlaneNormal(SplitPlaneNormal { left: 56, right: 57, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3395" }, vector: [0.1390, 0.0334, 0.1318, -0.2016, 0.1608, -0.0309, -0.0216, -0.0063, -0.0220, 0.0322, "other ..."] } }) +Tree 59: Descendants(Descendants { descendants: [5, 16, 25, 30, 35, 40, 41, 48, 49, 51, 60, 70, 85, 92] }) +Tree 60: Descendants(Descendants { descendants: [4, 8, 12, 17, 18, 23, 24, 27, 28, 52, 53, 55, 56, 59, 63, 64, 67, 68, 73, 75, 78, 83, 87, 88, 94, 99] }) +Tree 61: SplitPlaneNormal(SplitPlaneNormal { left: 59, right: 60, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.4039" }, vector: [0.3769, 0.0376, 0.1871, 0.1913, 0.3110, -0.2000, 0.1085, 0.1982, 0.1683, 0.0548, "other ..."] } }) +Tree 62: Descendants(Descendants { descendants: [2, 7, 10, 11, 13, 19, 31, 33, 42, 45, 46, 65, 66, 69, 72, 84, 91, 97, 98] }) +Tree 63: SplitPlaneNormal(SplitPlaneNormal { left: 61, right: 62, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3949" }, vector: [-0.0495, 0.0658, 0.2323, 0.1854, 0.3495, -0.0897, -0.1301, -0.1341, -0.1506, -0.0808, "other ..."] } }) +Tree 64: Descendants(Descendants { descendants: [1, 2, 3, 6, 10, 14, 25, 26, 27, 31, 40, 42, 44, 57, 62, 79, 81, 88, 90, 91, 97, 99] }) +Tree 65: Descendants(Descendants { descendants: [7, 9, 29, 33, 36, 38, 48, 50, 70, 86, 89, 93, 95, 96] }) +Tree 66: SplitPlaneNormal(SplitPlaneNormal { left: 64, right: 65, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.1602" }, vector: [0.1521, 0.1089, -0.1552, 0.0846, -0.2234, 0.0801, 0.0090, 0.3519, -0.3178, 0.2954, "other ..."] } }) +Tree 67: Descendants(Descendants { descendants: [17, 21, 37, 41, 46, 47, 52, 59, 60, 77, 85, 98] }) +Tree 68: Descendants(Descendants { descendants: [0, 4, 8, 11, 15, 18, 20, 28, 30, 32, 35, 39, 53, 66, 67, 69, 72, 73, 74, 75, 84] }) +Tree 69: Descendants(Descendants { descendants: [34, 45, 49, 54, 56, 63, 65, 76, 83, 92, 94] }) +Tree 70: SplitPlaneNormal(SplitPlaneNormal { left: 68, right: 69, normal: Leaf { header: NodeHeaderEuclidean { bias: "-1.0899" }, vector: [0.0031, 0.0549, 0.2685, 0.3145, 0.1133, 0.2947, -0.0886, -0.2127, 0.0126, 0.2376, "other ..."] } }) +Tree 71: Descendants(Descendants { descendants: [5, 12, 13, 16, 19, 22, 23, 24, 43, 51, 55, 58, 61, 64, 68, 71, 78, 80, 82, 87] }) +Tree 72: SplitPlaneNormal(SplitPlaneNormal { left: 70, right: 71, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.3044" }, vector: [-0.0145, 0.3141, -0.1642, -0.1171, -0.1654, -0.0233, -0.0565, -0.1028, 0.0166, 0.2478, "other ..."] } }) +Tree 73: SplitPlaneNormal(SplitPlaneNormal { left: 67, right: 72, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.1344" }, vector: [0.0129, 0.2435, 0.2349, -0.0484, 0.2422, -0.2681, 0.1833, -0.1857, -0.3249, -0.1537, "other ..."] } }) +Tree 74: Descendants(Descendants { descendants: [1, 16, 18, 21, 22, 23, 35, 37, 43, 47, 54, 55, 71, 78, 80, 82, 89, 90, 95, 98] }) +Tree 75: Descendants(Descendants { descendants: [15, 20, 24, 32, 34, 38, 49, 52, 53, 57, 58, 59, 60, 63, 68, 69, 75, 76, 79, 83, 84, 86, 88, 92, 94, 99] }) +Tree 76: SplitPlaneNormal(SplitPlaneNormal { left: 74, right: 75, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.3279" }, vector: [-0.2219, -0.1252, 0.0397, 0.2645, -0.0092, 0.1469, 0.0777, -0.1615, -0.1043, 0.0669, "other ..."] } }) +Tree 77: Descendants(Descendants { descendants: [0, 8, 11, 19, 30, 41, 42, 44, 45, 46, 51, 56, 64, 66, 67, 72, 73, 81] }) +Tree 78: Descendants(Descendants { descendants: [3, 5, 6, 9, 14, 17, 26, 27, 28, 40, 48, 77, 85, 87, 91, 93, 96] }) +Tree 79: SplitPlaneNormal(SplitPlaneNormal { left: 77, right: 78, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.0001" }, vector: [-0.0435, 0.3355, 0.3262, 0.0352, -0.2209, 0.0684, -0.1247, -0.0310, 0.1508, 0.0856, "other ..."] } }) +Tree 80: Descendants(Descendants { descendants: [2, 4, 7, 10, 12, 13, 25, 29, 31, 33, 36, 39, 50, 61, 62, 65, 70, 74, 97] }) +Tree 81: SplitPlaneNormal(SplitPlaneNormal { left: 79, right: 80, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.4929" }, vector: [-0.2899, -0.1000, -0.0545, -0.0710, 0.1562, -0.0686, 0.2158, 0.0031, -0.3984, 0.1937, "other ..."] } }) +Tree 82: Descendants(Descendants { descendants: [4, 18, 30, 34, 41, 43, 49, 51, 56, 61, 64, 76, 79, 84, 85, 88, 93, 94] }) +Tree 83: Descendants(Descendants { descendants: [8, 12, 17, 21, 25, 37, 40, 52, 60, 67, 69, 71, 73, 75, 78, 87, 99] }) +Tree 84: SplitPlaneNormal(SplitPlaneNormal { left: 82, right: 83, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.4767" }, vector: [0.1869, 0.1680, -0.0610, -0.1739, -0.2091, -0.3621, -0.2980, 0.0260, -0.2019, 0.1121, "other ..."] } }) +Tree 85: Descendants(Descendants { descendants: [2, 6, 13, 16, 19, 24, 26, 27, 28, 36, 42, 44, 45, 50, 54, 62, 65, 66, 72, 97] }) +Tree 86: Descendants(Descendants { descendants: [1, 10, 11, 31, 33, 46, 47, 70, 86, 91, 98] }) +Tree 87: SplitPlaneNormal(SplitPlaneNormal { left: 85, right: 86, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.2676" }, vector: [0.2076, -0.2436, -0.3938, 0.0593, -0.2604, 0.0931, -0.1010, 0.2622, 0.2030, -0.1545, "other ..."] } }) +Tree 88: SplitPlaneNormal(SplitPlaneNormal { left: 84, right: 87, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.0201" }, vector: [-0.1124, 0.1501, 0.1593, 0.1114, 0.1879, 0.1623, -0.2202, -0.1170, -0.3266, 0.2916, "other ..."] } }) +Tree 89: Descendants(Descendants { descendants: [0, 5, 7, 9, 14, 15, 22, 29, 32, 35, 39, 53, 55, 59, 74, 82, 89, 92, 96] }) +Tree 90: Descendants(Descendants { descendants: [3, 20, 23, 38, 48, 57, 58, 63, 68, 77, 80, 81, 83, 90, 95] }) +Tree 91: SplitPlaneNormal(SplitPlaneNormal { left: 89, right: 90, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.7103" }, vector: [-0.0174, 0.1012, -0.3409, 0.1977, 0.2175, -0.0333, -0.1155, -0.3879, 0.1104, 0.1831, "other ..."] } }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.8013, 0.2371, 0.6955, 0.8606, 0.5280, 0.2667, 0.6057, 0.9830, 0.9430, 0.0479, "other ..."] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.4199, 0.2620, 0.2655, 0.8414, 0.0192, 0.3828, 0.2561, 0.2692, 0.0368, 0.4624, "other ..."] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.1040, 0.9647, 0.8238, 0.5344, 0.4903, 0.4420, 0.7937, 0.4028, 0.2083, 0.3315, "other ..."] }) diff --git a/src/tests/writer.rs b/src/tests/writer.rs index c0de5ca..61138ae 100644 --- a/src/tests/writer.rs +++ b/src/tests/writer.rs @@ -281,9 +281,9 @@ fn write_vectors_until_there_is_a_split() { Dumping index 0 Root: Metadata { dimensions: 3, items: RoaringBitmap<[0, 1, 2, 3]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "2.3094" }, vector: [-0.5774, -0.5774, -0.5774] } }) - Tree 1: Descendants(Descendants { descendants: [2, 3] }) - Tree 2: Descendants(Descendants { descendants: [0, 1] }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3960" }, vector: [0.5774, 0.5774, 0.5774] } }) + Tree 1: Descendants(Descendants { descendants: [0, 1] }) + Tree 2: Descendants(Descendants { descendants: [2, 3] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 1.0000, 1.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 2.0000, 2.0000] }) @@ -404,13 +404,13 @@ fn overwrite_one_item_incremental() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 4, 5]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) - Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: Descendants(Descendants { descendants: [1, 2] }) - Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9571" }, vector: [1.0000, 0.0000] } }) - Tree 4: Descendants(Descendants { descendants: [3, 4] }) - Tree 5: Descendants(Descendants { descendants: [5] }) - Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "-4.2778" }, vector: [1.0000, 0.0000] } }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) + Tree 1: Descendants(Descendants { descendants: [2] }) + Tree 2: Descendants(Descendants { descendants: [0, 1] }) + Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.0000" }, vector: [-1.0000, 0.0000] } }) + Tree 4: Descendants(Descendants { descendants: [4, 5] }) + Tree 5: Descendants(Descendants { descendants: [3] }) + Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "3.7500" }, vector: [-1.0000, 0.0000] } }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) @@ -433,11 +433,11 @@ fn overwrite_one_item_incremental() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 4, 5]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) - Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: Descendants(Descendants { descendants: [1, 2] }) - Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9571" }, vector: [1.0000, 0.0000] } }) - Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 7, right: 8, normal: Leaf { header: NodeHeaderEuclidean { bias: "4.8750" }, vector: [-1.0000, 0.0000] } }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) + Tree 1: Descendants(Descendants { descendants: [2] }) + Tree 2: Descendants(Descendants { descendants: [0, 1] }) + Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.0000" }, vector: [-1.0000, 0.0000] } }) + Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 7, right: 8, normal: Leaf { header: NodeHeaderEuclidean { bias: "4.5625" }, vector: [-1.0000, 0.0000] } }) Tree 7: Descendants(Descendants { descendants: [3, 5] }) Tree 8: Descendants(Descendants { descendants: [4] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) @@ -606,9 +606,9 @@ fn delete_one_leaf_in_a_split() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.2500" }, vector: [-1.0000, 0.0000] } }) - Tree 1: Descendants(Descendants { descendants: [2] }) - Tree 2: Descendants(Descendants { descendants: [0, 1] }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.7143" }, vector: [1.0000, 0.0000] } }) + Tree 1: Descendants(Descendants { descendants: [0] }) + Tree 2: Descendants(Descendants { descendants: [1, 2] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) @@ -690,13 +690,13 @@ fn delete_one_item() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 4, 5]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) - Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: Descendants(Descendants { descendants: [1, 2] }) - Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9571" }, vector: [1.0000, 0.0000] } }) - Tree 4: Descendants(Descendants { descendants: [3, 4] }) - Tree 5: Descendants(Descendants { descendants: [5] }) - Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "-4.2778" }, vector: [1.0000, 0.0000] } }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) + Tree 1: Descendants(Descendants { descendants: [2] }) + Tree 2: Descendants(Descendants { descendants: [0, 1] }) + Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.0000" }, vector: [-1.0000, 0.0000] } }) + Tree 4: Descendants(Descendants { descendants: [4, 5] }) + Tree 5: Descendants(Descendants { descendants: [3] }) + Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "3.7500" }, vector: [-1.0000, 0.0000] } }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) @@ -718,11 +718,11 @@ fn delete_one_item() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 4, 5]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) - Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: Descendants(Descendants { descendants: [1, 2] }) - Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9571" }, vector: [1.0000, 0.0000] } }) - Tree 6: Descendants(Descendants { descendants: [4, 5] }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) + Tree 1: Descendants(Descendants { descendants: [2] }) + Tree 2: Descendants(Descendants { descendants: [0, 1] }) + Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.0000" }, vector: [-1.0000, 0.0000] } }) + Tree 4: Descendants(Descendants { descendants: [4, 5] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) @@ -744,9 +744,9 @@ fn delete_one_item() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 2, 4, 5]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) Tree 3: Descendants(Descendants { descendants: [0, 2] }) - Tree 6: Descendants(Descendants { descendants: [4, 5] }) + Tree 4: Descendants(Descendants { descendants: [4, 5] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) Item 4: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [4.0000, 0.0000] }) @@ -854,9 +854,9 @@ fn add_one_item_incrementally_to_create_a_split_node() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-1.2857" }, vector: [1.0000, 0.0000] } }) - Tree 1: Descendants(Descendants { descendants: [0, 1] }) - Tree 2: Descendants(Descendants { descendants: [2] }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.2778" }, vector: [-1.0000, 0.0000] } }) + Tree 1: Descendants(Descendants { descendants: [2] }) + Tree 2: Descendants(Descendants { descendants: [0, 1] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) @@ -881,13 +881,13 @@ fn add_one_item_incrementally() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 4, 5]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) - Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: Descendants(Descendants { descendants: [1, 2] }) - Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9571" }, vector: [1.0000, 0.0000] } }) - Tree 4: Descendants(Descendants { descendants: [3, 4] }) - Tree 5: Descendants(Descendants { descendants: [5] }) - Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "-4.2778" }, vector: [1.0000, 0.0000] } }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) + Tree 1: Descendants(Descendants { descendants: [2] }) + Tree 2: Descendants(Descendants { descendants: [0, 1] }) + Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.0000" }, vector: [-1.0000, 0.0000] } }) + Tree 4: Descendants(Descendants { descendants: [4, 5] }) + Tree 5: Descendants(Descendants { descendants: [3] }) + Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "3.7500" }, vector: [-1.0000, 0.0000] } }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) @@ -909,13 +909,15 @@ fn add_one_item_incrementally() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 4, 5, 25]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) - Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: Descendants(Descendants { descendants: [1, 2] }) - Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9571" }, vector: [1.0000, 0.0000] } }) - Tree 4: Descendants(Descendants { descendants: [3, 4] }) - Tree 5: Descendants(Descendants { descendants: [5, 25] }) - Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "-4.2778" }, vector: [1.0000, 0.0000] } }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) + Tree 1: Descendants(Descendants { descendants: [2] }) + Tree 2: Descendants(Descendants { descendants: [0, 1] }) + Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.0000" }, vector: [-1.0000, 0.0000] } }) + Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 7, right: 8, normal: Leaf { header: NodeHeaderEuclidean { bias: "14.9000" }, vector: [-1.0000, 0.0000] } }) + Tree 5: Descendants(Descendants { descendants: [3] }) + Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "3.7500" }, vector: [-1.0000, 0.0000] } }) + Tree 7: Descendants(Descendants { descendants: [25] }) + Tree 8: Descendants(Descendants { descendants: [4, 5] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) @@ -938,15 +940,17 @@ fn add_one_item_incrementally() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 4, 5, 8, 25]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) - Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: Descendants(Descendants { descendants: [1, 2] }) - Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9571" }, vector: [1.0000, 0.0000] } }) - Tree 4: Descendants(Descendants { descendants: [3, 4] }) - Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 7, right: 8, normal: Leaf { header: NodeHeaderEuclidean { bias: "-16.5000" }, vector: [1.0000, 0.0000] } }) - Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "-4.2778" }, vector: [1.0000, 0.0000] } }) - Tree 7: Descendants(Descendants { descendants: [5, 8] }) - Tree 8: Descendants(Descendants { descendants: [25] }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) + Tree 1: Descendants(Descendants { descendants: [2] }) + Tree 2: Descendants(Descendants { descendants: [0, 1] }) + Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.0000" }, vector: [-1.0000, 0.0000] } }) + Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 7, right: 8, normal: Leaf { header: NodeHeaderEuclidean { bias: "14.9000" }, vector: [-1.0000, 0.0000] } }) + Tree 5: Descendants(Descendants { descendants: [3] }) + Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "3.7500" }, vector: [-1.0000, 0.0000] } }) + Tree 7: Descendants(Descendants { descendants: [25] }) + Tree 8: SplitPlaneNormal(SplitPlaneNormal { left: 9, right: 10, normal: Leaf { header: NodeHeaderEuclidean { bias: "6.2778" }, vector: [-1.0000, 0.0000] } }) + Tree 9: Descendants(Descendants { descendants: [8] }) + Tree 10: Descendants(Descendants { descendants: [4, 5] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) @@ -977,12 +981,12 @@ fn delete_extraneous_tree() { Dumping index 0 Root: Metadata { dimensions: 4, items: RoaringBitmap<[0, 1, 2, 3, 4]>, roots: [0, 1], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "2.5000" }, vector: [-1.0000, 0.0000, 0.0000, 0.0000] } }) - Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 3, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.6429" }, vector: [-1.0000, 0.0000, 0.0000, 0.0000] } }) - Tree 2: Descendants(Descendants { descendants: [2, 3, 4] }) - Tree 3: Descendants(Descendants { descendants: [0, 1] }) - Tree 4: Descendants(Descendants { descendants: [3, 4] }) - Tree 5: Descendants(Descendants { descendants: [0, 1, 2] }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.5952" }, vector: [-1.0000, 0.0000, 0.0000, 0.0000] } }) + Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 3, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.2778" }, vector: [1.0000, 0.0000, 0.0000, 0.0000] } }) + Tree 2: Descendants(Descendants { descendants: [0, 1, 2] }) + Tree 3: Descendants(Descendants { descendants: [3, 4] }) + Tree 4: Descendants(Descendants { descendants: [2, 3, 4] }) + Tree 5: Descendants(Descendants { descendants: [0, 1] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000, 0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000, 0.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000, 0.0000, 0.0000] }) @@ -1000,12 +1004,12 @@ fn delete_extraneous_tree() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 4]>, roots: [0, 1], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "2.5000" }, vector: [-1.0000, 0.0000, 0.0000, 0.0000] } }) - Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 3, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.6429" }, vector: [-1.0000, 0.0000, 0.0000, 0.0000] } }) - Tree 2: Descendants(Descendants { descendants: [2, 3, 4] }) - Tree 3: Descendants(Descendants { descendants: [0, 1] }) - Tree 4: Descendants(Descendants { descendants: [3, 4] }) - Tree 5: Descendants(Descendants { descendants: [0, 1, 2] }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.5952" }, vector: [-1.0000, 0.0000, 0.0000, 0.0000] } }) + Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 3, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.2778" }, vector: [1.0000, 0.0000, 0.0000, 0.0000] } }) + Tree 2: Descendants(Descendants { descendants: [0, 1, 2] }) + Tree 3: Descendants(Descendants { descendants: [3, 4] }) + Tree 4: Descendants(Descendants { descendants: [2, 3, 4] }) + Tree 5: Descendants(Descendants { descendants: [0, 1] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000, 0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000, 0.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000, 0.0000, 0.0000] }) @@ -1023,9 +1027,9 @@ fn delete_extraneous_tree() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 4]>, roots: [1], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 3, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.6429" }, vector: [-1.0000, 0.0000, 0.0000, 0.0000] } }) - Tree 2: Descendants(Descendants { descendants: [2, 3, 4] }) - Tree 3: Descendants(Descendants { descendants: [0, 1] }) + Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 3, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.2778" }, vector: [1.0000, 0.0000, 0.0000, 0.0000] } }) + Tree 2: Descendants(Descendants { descendants: [0, 1, 2] }) + Tree 3: Descendants(Descendants { descendants: [3, 4] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000, 0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000, 0.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000, 0.0000, 0.0000] }) @@ -1053,13 +1057,13 @@ fn create_root_split_node_with_empty_child() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 4, 5]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) - Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: Descendants(Descendants { descendants: [1, 2] }) - Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9571" }, vector: [1.0000, 0.0000] } }) - Tree 4: Descendants(Descendants { descendants: [3, 4] }) - Tree 5: Descendants(Descendants { descendants: [5] }) - Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "-4.2778" }, vector: [1.0000, 0.0000] } }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) + Tree 1: Descendants(Descendants { descendants: [2] }) + Tree 2: Descendants(Descendants { descendants: [0, 1] }) + Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.0000" }, vector: [-1.0000, 0.0000] } }) + Tree 4: Descendants(Descendants { descendants: [4, 5] }) + Tree 5: Descendants(Descendants { descendants: [3] }) + Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "3.7500" }, vector: [-1.0000, 0.0000] } }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) @@ -1083,9 +1087,9 @@ fn create_root_split_node_with_empty_child() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 2, 3, 4]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) Tree 3: Descendants(Descendants { descendants: [0, 2] }) - Tree 4: Descendants(Descendants { descendants: [3, 4] }) + Tree 6: Descendants(Descendants { descendants: [3, 4] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) Item 3: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [3.0000, 0.0000] }) @@ -1105,9 +1109,9 @@ fn create_root_split_node_with_empty_child() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[2, 3, 4]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 4, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) Tree 3: Descendants(Descendants { descendants: [2] }) - Tree 4: Descendants(Descendants { descendants: [3, 4] }) + Tree 6: Descendants(Descendants { descendants: [3, 4] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) Item 3: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [3.0000, 0.0000] }) Item 4: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [4.0000, 0.0000] }) @@ -1132,13 +1136,13 @@ fn reuse_node_id() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 4, 5]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) - Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: Descendants(Descendants { descendants: [1, 2] }) - Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9571" }, vector: [1.0000, 0.0000] } }) - Tree 4: Descendants(Descendants { descendants: [3, 4] }) - Tree 5: Descendants(Descendants { descendants: [5] }) - Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "-4.2778" }, vector: [1.0000, 0.0000] } }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) + Tree 1: Descendants(Descendants { descendants: [2] }) + Tree 2: Descendants(Descendants { descendants: [0, 1] }) + Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.0000" }, vector: [-1.0000, 0.0000] } }) + Tree 4: Descendants(Descendants { descendants: [4, 5] }) + Tree 5: Descendants(Descendants { descendants: [3] }) + Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "3.7500" }, vector: [-1.0000, 0.0000] } }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) @@ -1160,10 +1164,10 @@ fn reuse_node_id() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 5]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) - Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: Descendants(Descendants { descendants: [1, 2] }) - Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9571" }, vector: [1.0000, 0.0000] } }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) + Tree 1: Descendants(Descendants { descendants: [2] }) + Tree 2: Descendants(Descendants { descendants: [0, 1] }) + Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.0000" }, vector: [-1.0000, 0.0000] } }) Tree 6: Descendants(Descendants { descendants: [3, 5] }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000] }) @@ -1185,13 +1189,13 @@ fn reuse_node_id() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 4, 5]>, roots: [0], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) - Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: Descendants(Descendants { descendants: [1, 2] }) - Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9571" }, vector: [1.0000, 0.0000] } }) - Tree 4: Descendants(Descendants { descendants: [3] }) - Tree 5: Descendants(Descendants { descendants: [4, 5] }) - Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "-3.6111" }, vector: [1.0000, 0.0000] } }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) + Tree 1: Descendants(Descendants { descendants: [2] }) + Tree 2: Descendants(Descendants { descendants: [0, 1] }) + Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.0000" }, vector: [-1.0000, 0.0000] } }) + Tree 4: Descendants(Descendants { descendants: [5] }) + Tree 5: Descendants(Descendants { descendants: [3, 4] }) + Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "4.2000" }, vector: [-1.0000, 0.0000] } }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) @@ -1212,20 +1216,20 @@ fn reuse_node_id() { Dumping index 0 Root: Metadata { dimensions: 2, items: RoaringBitmap<[0, 1, 2, 3, 4, 5]>, roots: [0, 7], distance: "euclidean" } Version: Version { major: 0, minor: 7, patch: 0 } - Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) - Tree 1: Descendants(Descendants { descendants: [0] }) - Tree 2: Descendants(Descendants { descendants: [1, 2] }) - Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "-0.9571" }, vector: [1.0000, 0.0000] } }) - Tree 4: Descendants(Descendants { descendants: [3] }) - Tree 5: Descendants(Descendants { descendants: [4, 5] }) - Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "-3.6111" }, vector: [1.0000, 0.0000] } }) - Tree 7: SplitPlaneNormal(SplitPlaneNormal { left: 10, right: 13, normal: Leaf { header: NodeHeaderEuclidean { bias: "2.2500" }, vector: [-1.0000, 0.0000] } }) - Tree 8: Descendants(Descendants { descendants: [5] }) - Tree 9: Descendants(Descendants { descendants: [3, 4] }) - Tree 10: SplitPlaneNormal(SplitPlaneNormal { left: 8, right: 9, normal: Leaf { header: NodeHeaderEuclidean { bias: "4.1667" }, vector: [-1.0000, 0.0000] } }) - Tree 11: Descendants(Descendants { descendants: [0, 1] }) - Tree 12: Descendants(Descendants { descendants: [2] }) - Tree 13: SplitPlaneNormal(SplitPlaneNormal { left: 11, right: 12, normal: Leaf { header: NodeHeaderEuclidean { bias: "-1.1667" }, vector: [1.0000, 0.0000] } }) + Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 3, right: 6, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.7500" }, vector: [1.0000, 0.0000] } }) + Tree 1: Descendants(Descendants { descendants: [2] }) + Tree 2: Descendants(Descendants { descendants: [0, 1] }) + Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 1, right: 2, normal: Leaf { header: NodeHeaderEuclidean { bias: "1.0000" }, vector: [-1.0000, 0.0000] } }) + Tree 4: Descendants(Descendants { descendants: [5] }) + Tree 5: Descendants(Descendants { descendants: [3, 4] }) + Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderEuclidean { bias: "4.2000" }, vector: [-1.0000, 0.0000] } }) + Tree 7: SplitPlaneNormal(SplitPlaneNormal { left: 10, right: 13, normal: Leaf { header: NodeHeaderEuclidean { bias: "-2.3714" }, vector: [1.0000, 0.0000] } }) + Tree 8: Descendants(Descendants { descendants: [1, 2] }) + Tree 9: Descendants(Descendants { descendants: [0] }) + Tree 10: SplitPlaneNormal(SplitPlaneNormal { left: 8, right: 9, normal: Leaf { header: NodeHeaderEuclidean { bias: "0.8714" }, vector: [-1.0000, 0.0000] } }) + Tree 11: Descendants(Descendants { descendants: [4, 5] }) + Tree 12: Descendants(Descendants { descendants: [3] }) + Tree 13: SplitPlaneNormal(SplitPlaneNormal { left: 11, right: 12, normal: Leaf { header: NodeHeaderEuclidean { bias: "3.6250" }, vector: [-1.0000, 0.0000] } }) Item 0: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [0.0000, 0.0000] }) Item 1: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [1.0000, 0.0000] }) Item 2: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [2.0000, 0.0000] }) diff --git a/src/writer.rs b/src/writer.rs index a6b0d9b..d6c1b73 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use std::cell::RefCell; use std::path::PathBuf; use std::sync::atomic::AtomicU32; -use std::sync::Arc; +use std::sync::{mpsc, Arc}; use heed::types::{Bytes, DecodeIgnore, Unit}; use heed::{MdbError, PutFlags, RoTxn, RwTxn}; @@ -545,37 +545,27 @@ impl Writer { descendants.insert(new_id, item_indices.clone()); } - let mut new_descendants = IntMap::::default(); + let (error_snd, error_rcv) = mpsc::channel::(); rayon::scope(|s| { let frozen_reader = &frozen_reader; - for (descendant_id, mut item_indices) in descendants.into_iter() { - // TODO: Unwrap is NOT safe and must be handled - let old_items = frozen_reader.trees.get(descendant_id).unwrap(); - if let Some(old_items) = old_items { - item_indices |= old_items.descendants().unwrap().descendants.as_ref(); - } - if self.fit_in_descendant(options, item_indices.len()) { - new_descendants.insert(descendant_id, item_indices); - } else { - let rng = StdRng::from_seed(rng.gen()); - let files_tls = files_tls.clone(); - s.spawn(move |s| { - // TODO: find a way to return the error and stop the indexing process - self.incremental_index_large_descendant( - rng, - options, - s, - (descendant_id, item_indices), - frozen_reader, - files_tls, - ) - .unwrap(); - }); + let files_tls = files_tls.clone(); + let error_snd = error_snd.clone(); + + // Spawn a thread that will create all the tasks + s.spawn(move |s| { + let rng = StdRng::from_seed(rng.gen()); + let ret = self.insert_descendants_in_file_and_spawn_tasks(rng, options, s, &frozen_reader, files_tls, descendants); + if let Err(e) = ret { + error_snd.send(e).unwrap(); } - } + }); }); + if let Ok(e) = error_rcv.try_recv() { + return Err(e); + } + let files_tls = Arc::into_inner(files_tls).expect("Threads have all finished their works"); for file in files_tls.into_iter() { let tmp_nodes = file.into_inner().into_bytes_reader()?; @@ -588,14 +578,6 @@ impl Writer { } } - for (descendant_id, item_indices) in new_descendants.into_iter() { - self.database.put( - wtxn, - &Key::tree(self.index, descendant_id), - &Node::Descendants(Descendants { descendants: Cow::Borrowed(&item_indices) }), - )?; - } - tracing::debug!("write the metadata..."); (options.progress)(WriterProgress { main: MainStep::WriteTheMetadata, sub: None }); let metadata = Metadata { @@ -705,6 +687,30 @@ impl Writer { )?; } + drop(tmp_node); + self.insert_descendants_in_file_and_spawn_tasks(rng, options, scope, frozen_reader, tmp_nodes, descendants)?; + + Ok(()) + } + + /// Explore the IntMap of descendants and when a descendant is too large to fit in memory, spawn a task to index it. + /// Otherwise, insert the descendant in the tempfile. + fn insert_descendants_in_file_and_spawn_tasks<'scope, R: Rng + SeedableRng + Send + Sync>( + &'scope self, + mut rng: R, + options: &'scope BuildOption, + scope: &Scope<'scope>, + frozen_reader: &'scope FrozzenReader<'_, D>, + tmp_nodes: Arc>>>, + descendants: IntMap, + ) -> Result<(), Error> { + let tmp_node = tmp_nodes.get_or_try(|| match self.tmpdir.as_ref() { + Some(path) => TmpNodes::new_in(path).map(RefCell::new), + None => TmpNodes::new().map(RefCell::new), + })?; + // Safe to borrow mut here because we're the only thread running with this variable + let mut tmp_node = tmp_node.borrow_mut(); + for (item_id, item_indices) in descendants.into_iter() { if self.fit_in_descendant(options, item_indices.len()) { tmp_node.put( @@ -1265,8 +1271,8 @@ fn insert_items_in_descendants_from_frozen_reader( opt.cancelled()?; match frozen_reader.trees.get(current_node)?.unwrap() { Node::Leaf(_) => unreachable!(), - Node::Descendants(Descendants { descendants: _ }) => { - descendants_to_update.insert(current_node, to_insert.clone()); + Node::Descendants(Descendants { descendants }) => { + descendants_to_update.insert(current_node, descendants.into_owned() | to_insert); } Node::SplitPlaneNormal(SplitPlaneNormal { normal, left, right }) => { // Split the to_insert into two bitmaps on the left and right of this normal From d4d646df89a7f18e7bbcadee520484cc81e32b4e Mon Sep 17 00:00:00 2001 From: Tamo Date: Mon, 16 Jun 2025 16:33:34 +0200 Subject: [PATCH 12/24] handle error properly in the rayon pool --- Cargo.toml | 1 + src/writer.rs | 52 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0b3d24e..c879bbf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ nohash = "0.2.0" page_size = "0.6.0" enum-iterator = "2.1.0" thread_local = "1.1.8" +crossbeam = "0.8.4" [dev-dependencies] anyhow = "1.0.95" diff --git a/src/writer.rs b/src/writer.rs index d6c1b73..c7feb8e 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -3,8 +3,9 @@ use std::borrow::Cow; use std::cell::RefCell; use std::path::PathBuf; use std::sync::atomic::AtomicU32; -use std::sync::{mpsc, Arc}; +use std::sync::{Arc}; +use crossbeam::channel::{bounded, Sender}; use heed::types::{Bytes, DecodeIgnore, Unit}; use heed::{MdbError, PutFlags, RoTxn, RwTxn}; use nohash::{BuildNoHashHasher, IntMap}; @@ -545,7 +546,10 @@ impl Writer { descendants.insert(new_id, item_indices.clone()); } - let (error_snd, error_rcv) = mpsc::channel::(); + // When a task fails, a message must be sent in this channel. + // When a taks starts it must check if the channel contains something and stop asap. + // The channel will be openend only after all the tasks have been stopped. + let (error_snd, error_rcv) = bounded(1); rayon::scope(|s| { let frozen_reader = &frozen_reader; @@ -555,9 +559,9 @@ impl Writer { // Spawn a thread that will create all the tasks s.spawn(move |s| { let rng = StdRng::from_seed(rng.gen()); - let ret = self.insert_descendants_in_file_and_spawn_tasks(rng, options, s, &frozen_reader, files_tls, descendants); + let ret = self.insert_descendants_in_file_and_spawn_tasks(rng, options, &error_snd, s, &frozen_reader, files_tls, descendants); if let Err(e) = ret { - error_snd.send(e).unwrap(); + let _ = error_snd.send(e); } }); }); @@ -632,6 +636,7 @@ impl Writer { &'scope self, mut rng: R, options: &'scope BuildOption, + error_snd: &Sender, scope: &Scope<'scope>, descendant: (ItemId, RoaringBitmap), frozen_reader: &'scope FrozzenReader, @@ -642,6 +647,9 @@ impl Writer { sub: None, }); options.cancelled()?; + if error_snd.is_full() { + return Ok(()); + } let tmp_node = tmp_nodes.get_or_try(|| match self.tmpdir.as_ref() { Some(path) => TmpNodes::new_in(path).map(RefCell::new), @@ -663,6 +671,7 @@ impl Writer { let (root_id, _nb_new_tree_nodes) = self.make_tree_in_file( options, frozen_reader, + error_snd, &mut rng, &items_for_tree, &mut descendants, @@ -675,6 +684,9 @@ impl Writer { fit_in_memory::(available_memory, &mut to_insert, self.dimensions, &mut rng) { options.cancelled()?; + if error_snd.is_full() { + return Ok(()); + } insert_items_in_descendants_from_tmpfile( options, @@ -688,7 +700,7 @@ impl Writer { } drop(tmp_node); - self.insert_descendants_in_file_and_spawn_tasks(rng, options, scope, frozen_reader, tmp_nodes, descendants)?; + self.insert_descendants_in_file_and_spawn_tasks(rng, options, &error_snd, scope, frozen_reader, tmp_nodes, descendants)?; Ok(()) } @@ -699,11 +711,16 @@ impl Writer { &'scope self, mut rng: R, options: &'scope BuildOption, + error_snd: &Sender, scope: &Scope<'scope>, frozen_reader: &'scope FrozzenReader<'_, D>, tmp_nodes: Arc>>>, descendants: IntMap, ) -> Result<(), Error> { + options.cancelled()?; + if error_snd.is_full() { + return Ok(()); + } let tmp_node = tmp_nodes.get_or_try(|| match self.tmpdir.as_ref() { Some(path) => TmpNodes::new_in(path).map(RefCell::new), None => TmpNodes::new().map(RefCell::new), @@ -712,6 +729,10 @@ impl Writer { let mut tmp_node = tmp_node.borrow_mut(); for (item_id, item_indices) in descendants.into_iter() { + options.cancelled()?; + if error_snd.is_full() { + return Ok(()); + } if self.fit_in_descendant(options, item_indices.len()) { tmp_node.put( item_id, @@ -720,17 +741,20 @@ impl Writer { } else { let tmp_nodes = tmp_nodes.clone(); let rng = StdRng::from_seed(rng.gen()); + let error_snd = error_snd.clone(); scope.spawn(move |s| { - // TODO: Find a way to return the error and stop the indexing process - self.incremental_index_large_descendant( + let ret = self.incremental_index_large_descendant( rng, options, + &error_snd, s, (item_id, item_indices), frozen_reader, tmp_nodes, - ) - .unwrap(); + ); + if let Err(e) = ret { + let _ = error_snd.send(e); + } }); } } @@ -873,7 +897,6 @@ impl Writer { None => TmpNodes::new()?, }; - // TODO: Parallelize for root in roots.iter_mut() { options.cancelled()?; let (new_root, _) = @@ -1050,6 +1073,7 @@ impl Writer { &self, opt: &BuildOption, reader: &FrozzenReader, + error_snd: &Sender, rng: &mut R, item_indices: &RoaringBitmap, descendants: &mut IntMap, @@ -1057,6 +1081,10 @@ impl Writer { tmp_nodes: &mut TmpNodes, ) -> Result<(ItemId, u64)> { opt.cancelled()?; + if error_snd.is_full() { + // We can return anything as the whole process is being stopped and nothing will be written + return Ok((0, 0)); + } if self.fit_in_descendant(opt, item_indices.len()) { let item_id = next_id.map(Ok).unwrap_or_else(|| reader.concurrent_node_ids.next())?; // Don't write the descendants to the tmp nodes yet because they may become too large later @@ -1110,10 +1138,11 @@ impl Writer { }; let (left, l) = - self.make_tree_in_file(opt, reader, rng, &children_left, descendants, None, tmp_nodes)?; + self.make_tree_in_file(opt, reader, error_snd, rng, &children_left, descendants, None, tmp_nodes)?; let (right, r) = self.make_tree_in_file( opt, reader, + error_snd, rng, &children_right, descendants, @@ -1380,7 +1409,6 @@ fn insert_items_in_descendants_from_tmpfile( /// Returns the items from the `to_insert` that fit in memory. /// If there is no items to insert anymore, returns `None`. /// If everything fits in memory, returns the `to_insert` bitmap. -/// TODO: We should randomize the items selected. fn fit_in_memory( memory: usize, to_insert: &mut RoaringBitmap, From c1874ff12c40d35eb777c55a69c746e6df7470d7 Mon Sep 17 00:00:00 2001 From: Tamo Date: Mon, 16 Jun 2025 16:37:55 +0200 Subject: [PATCH 13/24] use try_send instead on send in case two errors happens at the same moment. We don't want one thread to stay stuck forever --- src/writer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/writer.rs b/src/writer.rs index c7feb8e..0e42cfe 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -561,7 +561,7 @@ impl Writer { let rng = StdRng::from_seed(rng.gen()); let ret = self.insert_descendants_in_file_and_spawn_tasks(rng, options, &error_snd, s, &frozen_reader, files_tls, descendants); if let Err(e) = ret { - let _ = error_snd.send(e); + let _ = error_snd.try_send(e); } }); }); @@ -753,7 +753,7 @@ impl Writer { tmp_nodes, ); if let Err(e) = ret { - let _ = error_snd.send(e); + let _ = error_snd.try_send(e); } }); } From 2face0ec871f3ea0fa96a1f432d4444bdfecdb40 Mon Sep 17 00:00:00 2001 From: Tamo Date: Mon, 16 Jun 2025 16:41:15 +0200 Subject: [PATCH 14/24] fmt+lints --- src/metadata.rs | 2 +- src/writer.rs | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/metadata.rs b/src/metadata.rs index 6b0814a..79c5113 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -23,7 +23,7 @@ impl<'a> heed::BytesEncode<'a> for MetadataCodec { fn bytes_encode(item: &'a Self::EItem) -> Result, BoxedError> { let Metadata { dimensions, items, roots, distance } = item; - debug_assert!(!distance.as_bytes().iter().any(|&b| b == 0)); + debug_assert!(!distance.as_bytes().contains(&0)); let mut output = Vec::with_capacity( size_of::() diff --git a/src/writer.rs b/src/writer.rs index 0e42cfe..33f0ec2 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use std::cell::RefCell; use std::path::PathBuf; use std::sync::atomic::AtomicU32; -use std::sync::{Arc}; +use std::sync::Arc; use crossbeam::channel::{bounded, Sender}; use heed::types::{Bytes, DecodeIgnore, Unit}; @@ -559,7 +559,15 @@ impl Writer { // Spawn a thread that will create all the tasks s.spawn(move |s| { let rng = StdRng::from_seed(rng.gen()); - let ret = self.insert_descendants_in_file_and_spawn_tasks(rng, options, &error_snd, s, &frozen_reader, files_tls, descendants); + let ret = self.insert_descendants_in_file_and_spawn_tasks( + rng, + options, + &error_snd, + s, + frozen_reader, + files_tls, + descendants, + ); if let Err(e) = ret { let _ = error_snd.try_send(e); } @@ -632,6 +640,7 @@ impl Writer { /// Returns the new descendants that are ready to store in the database. /// Push more tasks to the scope for all the descendants that are still too large to fit in memory. /// Write the tree squeleton to its local tmp file. That file must be written to the DB at the end. + #[allow(clippy::too_many_arguments)] fn incremental_index_large_descendant<'scope, R: Rng + SeedableRng + Send + Sync>( &'scope self, mut rng: R, @@ -700,13 +709,22 @@ impl Writer { } drop(tmp_node); - self.insert_descendants_in_file_and_spawn_tasks(rng, options, &error_snd, scope, frozen_reader, tmp_nodes, descendants)?; + self.insert_descendants_in_file_and_spawn_tasks( + rng, + options, + error_snd, + scope, + frozen_reader, + tmp_nodes, + descendants, + )?; Ok(()) } /// Explore the IntMap of descendants and when a descendant is too large to fit in memory, spawn a task to index it. /// Otherwise, insert the descendant in the tempfile. + #[allow(clippy::too_many_arguments)] fn insert_descendants_in_file_and_spawn_tasks<'scope, R: Rng + SeedableRng + Send + Sync>( &'scope self, mut rng: R, @@ -1137,8 +1155,16 @@ impl Writer { ) }; - let (left, l) = - self.make_tree_in_file(opt, reader, error_snd, rng, &children_left, descendants, None, tmp_nodes)?; + let (left, l) = self.make_tree_in_file( + opt, + reader, + error_snd, + rng, + &children_left, + descendants, + None, + tmp_nodes, + )?; let (right, r) = self.make_tree_in_file( opt, reader, From 5b8efc03e8b84e44987e6a713c4f9aeddbb2d5eb Mon Sep 17 00:00:00 2001 From: Tamo Date: Tue, 17 Jun 2025 10:11:20 +0200 Subject: [PATCH 15/24] remove debug prints --- src/writer.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/writer.rs b/src/writer.rs index 33f0ec2..c6a6d53 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -977,13 +977,11 @@ impl Writer { match (left_items, right_items) { (Some(left_items), right_items) if left_items.is_empty() => { - println!("left_items is empty"); tmp_nodes.remove(new_left); tmp_nodes.remove(current_node); Ok((new_right, right_items)) } (left_items, Some(right_items)) if right_items.is_empty() => { - println!("right_items is empty"); tmp_nodes.remove(new_right); tmp_nodes.remove(current_node); Ok((new_left, left_items)) From e9209c2458e72916f6f21cc2086379381193f949 Mon Sep 17 00:00:00 2001 From: Tamo Date: Tue, 17 Jun 2025 10:35:28 +0200 Subject: [PATCH 16/24] remove new_fit_in_memory --- src/parallel.rs | 58 +------------------------------------------------ 1 file changed, 1 insertion(+), 57 deletions(-) diff --git a/src/parallel.rs b/src/parallel.rs index 72deb04..0ab9a62 100644 --- a/src/parallel.rs +++ b/src/parallel.rs @@ -8,7 +8,7 @@ use std::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering}; use heed::types::Bytes; use heed::{BytesDecode, BytesEncode, RoTxn}; use memmap2::Mmap; -use nohash::{BuildNoHashHasher, IntMap, IntSet}; +use nohash::{BuildNoHashHasher, IntMap}; use rand::seq::index; use rand::Rng; use roaring::{RoaringBitmap, RoaringTreemap}; @@ -287,62 +287,6 @@ impl<'t, D: Distance> ImmutableLeafs<'t, D> { Ok(ImmutableLeafs { leafs, constant_length, _marker: marker::PhantomData }) } - /// Creates the structure by fetching all the leaf pointers - /// and keeping the transaction making the pointers valid. - /// Do not take more items than memory allows. - /// Remove from the list of candidates all the items that were selected and return them. - pub fn new_fits_in_memory( - rtxn: &'t RoTxn, - database: Database, - index: u16, - candidates: &mut RoaringBitmap, - memory: usize, - ) -> heed::Result<(Self, RoaringBitmap)> { - let page_size = page_size::get(); - let nb_page_allowed = (memory as f64 / page_size as f64).floor() as usize; - - let mut leafs = IntMap::with_capacity_and_hasher( - nb_page_allowed.min(candidates.len() as usize), // We cannot approximate the capacity better because we don't know yet the size of an item - BuildNoHashHasher::default(), - ); - let mut pages_used = IntSet::with_capacity_and_hasher( - nb_page_allowed.min(candidates.len() as usize), - BuildNoHashHasher::default(), - ); - let mut selected_items = RoaringBitmap::new(); - let mut constant_length = None; - - while let Some(item_id) = candidates.select(0) { - let bytes = - database.remap_data_type::().get(rtxn, &Key::item(index, item_id))?.unwrap(); - assert_eq!(*constant_length.get_or_insert(bytes.len()), bytes.len()); - - let ptr = bytes.as_ptr(); - let addr = ptr as usize; - let start = addr / page_size; - let end = (addr + bytes.len()) / page_size; - - pages_used.insert(start); - if start != end { - pages_used.insert(end); - } - - if pages_used.len() >= nb_page_allowed && leafs.len() >= 200 { - break; - } - - // Safe because the items comes from another roaring bitmap - selected_items.push(item_id); - candidates.remove_smallest(1); - leafs.insert(item_id, ptr); - } - - Ok(( - ImmutableLeafs { leafs, constant_length, _marker: marker::PhantomData }, - selected_items, - )) - } - /// Returns the leafs identified by the given ID. pub fn get(&self, item_id: ItemId) -> heed::Result>> { let len = match self.constant_length { From af2cdcae43ab5ca6b77ad6cad50df5e64af43b82 Mon Sep 17 00:00:00 2001 From: Tamo Date: Tue, 17 Jun 2025 14:37:03 +0200 Subject: [PATCH 17/24] fix panic when we have low memory --- src/writer.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/writer.rs b/src/writer.rs index c6a6d53..5a0e3a5 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1382,12 +1382,12 @@ fn insert_items_in_descendants_from_tmpfile( descendants_to_update: &mut IntMap, ) -> Result<()> { opt.cancelled()?; - match tmp_nodes.get(current_node)?.unwrap() { - Node::Leaf(_) => unreachable!(), - Node::Descendants(Descendants { descendants: _ }) => { - descendants_to_update.insert(current_node, to_insert.clone()); + match tmp_nodes.get(current_node)? { + Some(Node::Leaf(_) | Node::Descendants(_)) => unreachable!(), + None => { + *descendants_to_update.get_mut(¤t_node).unwrap() |= to_insert; } - Node::SplitPlaneNormal(SplitPlaneNormal { normal, left, right }) => { + Some(Node::SplitPlaneNormal(SplitPlaneNormal { normal, left, right })) => { // Split the to_insert into two bitmaps on the left and right of this normal let mut left_ids = RoaringBitmap::new(); let mut right_ids = RoaringBitmap::new(); From ecf0df4ae227be68306bc3ab78fecfaf55bc1e62 Mon Sep 17 00:00:00 2001 From: Tamo Date: Tue, 17 Jun 2025 15:31:05 +0200 Subject: [PATCH 18/24] check for error when inserting elements in a tree --- src/tests/writer.rs | 1 - src/writer.rs | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tests/writer.rs b/src/tests/writer.rs index 61138ae..f504535 100644 --- a/src/tests/writer.rs +++ b/src/tests/writer.rs @@ -1072,7 +1072,6 @@ fn create_root_split_node_with_empty_child() { Item 5: Leaf(Leaf { header: NodeHeaderEuclidean { bias: "0.0000" }, vector: [5.0000, 0.0000] }) "#); - println!("HEEEEEERE"); let mut wtxn = handle.env.write_txn().unwrap(); let writer = Writer::new(handle.database, 0, 2); diff --git a/src/writer.rs b/src/writer.rs index 5a0e3a5..e5e2344 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -701,6 +701,7 @@ impl Writer { options, frozen_reader, &mut tmp_node, + error_snd, &mut rng, descendant_id, &to_insert, @@ -1376,12 +1377,16 @@ fn insert_items_in_descendants_from_tmpfile( frozen_reader: &FrozzenReader, // Must be mutable because we're going to seek and read in it tmp_nodes: &mut TmpNodes, + error_snd: &Sender, rng: &mut R, current_node: ItemId, to_insert: &RoaringBitmap, descendants_to_update: &mut IntMap, ) -> Result<()> { opt.cancelled()?; + if error_snd.is_full() { + return Ok(()); + } match tmp_nodes.get(current_node)? { Some(Node::Leaf(_) | Node::Descendants(_)) => unreachable!(), None => { @@ -1411,6 +1416,7 @@ fn insert_items_in_descendants_from_tmpfile( opt, frozen_reader, tmp_nodes, + error_snd, rng, left, &left_ids, @@ -1420,6 +1426,7 @@ fn insert_items_in_descendants_from_tmpfile( opt, frozen_reader, tmp_nodes, + error_snd, rng, right, &right_ids, From 5262b0866ed6a0b8fe529b170a1700fe4a47ebbd Mon Sep 17 00:00:00 2001 From: Tamo Date: Tue, 17 Jun 2025 16:02:25 +0200 Subject: [PATCH 19/24] fix multiple bugs --- src/writer.rs | 85 ++++++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/src/writer.rs b/src/writer.rs index e5e2344..7badd6e 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1348,22 +1348,26 @@ fn insert_items_in_descendants_from_frozen_reader( } } - insert_items_in_descendants_from_frozen_reader( - opt, - frozen_reader, - rng, - left, - &left_ids, - descendants_to_update, - )?; - insert_items_in_descendants_from_frozen_reader( - opt, - frozen_reader, - rng, - right, - &right_ids, - descendants_to_update, - )?; + if !left_ids.is_empty() { + insert_items_in_descendants_from_frozen_reader( + opt, + frozen_reader, + rng, + left, + &left_ids, + descendants_to_update, + )?; + } + if !right_ids.is_empty() { + insert_items_in_descendants_from_frozen_reader( + opt, + frozen_reader, + rng, + right, + &right_ids, + descendants_to_update, + )?; + } } } Ok(()) @@ -1412,26 +1416,30 @@ fn insert_items_in_descendants_from_tmpfile( } } - insert_items_in_descendants_from_tmpfile( - opt, - frozen_reader, - tmp_nodes, - error_snd, - rng, - left, - &left_ids, - descendants_to_update, - )?; - insert_items_in_descendants_from_tmpfile( - opt, - frozen_reader, - tmp_nodes, - error_snd, - rng, - right, - &right_ids, - descendants_to_update, - )?; + if !left_ids.is_empty() { + insert_items_in_descendants_from_tmpfile( + opt, + frozen_reader, + tmp_nodes, + error_snd, + rng, + left, + &left_ids, + descendants_to_update, + )?; + } + if !right_ids.is_empty() { + insert_items_in_descendants_from_tmpfile( + opt, + frozen_reader, + tmp_nodes, + error_snd, + rng, + right, + &right_ids, + descendants_to_update, + )?; + } } } Ok(()) @@ -1479,8 +1487,9 @@ fn fit_in_memory( for _ in 0..nb_items { let idx = rng.gen_range(0..to_insert.len()); // Safe to unwrap because we know nb_items is smaller than the number of items in the bitmap - items.push(to_insert.select(idx as u32).unwrap()); - to_insert.remove_smallest(idx); + let item = to_insert.select(idx as u32).unwrap(); + items.push(item); + to_insert.remove(item); } Some(items) From fa626508854b33d0e6994ba601bf27d9c1315eea Mon Sep 17 00:00:00 2001 From: Tamo Date: Tue, 17 Jun 2025 17:14:33 +0200 Subject: [PATCH 20/24] fix a new bug and add unit tests on fit_in_memory --- src/tests/fit_in_memory.rs | 73 ++++++++++++++++++++++++++++++++++++++ src/tests/mod.rs | 1 + src/writer.rs | 13 +++++-- 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 src/tests/fit_in_memory.rs diff --git a/src/tests/fit_in_memory.rs b/src/tests/fit_in_memory.rs new file mode 100644 index 0000000..52521cf --- /dev/null +++ b/src/tests/fit_in_memory.rs @@ -0,0 +1,73 @@ +use crate::writer::fit_in_memory; +use crate::distances::Euclidean; +use crate::distance::Distance; +use rand::rngs::StdRng; +use rand::SeedableRng; +use roaring::RoaringBitmap; + +#[test] +fn test_empty_bitmap() { + let mut rng = StdRng::seed_from_u64(28); + let mut bitmap = RoaringBitmap::new(); + let result = fit_in_memory::(1024 * 1024, &mut bitmap, 128, &mut rng); + assert!(result.is_none()); +} + +#[test] +fn test_all_items_fit() { + let mut rng = StdRng::seed_from_u64(35); + let mut bitmap = RoaringBitmap::from_sorted_iter(0..100).unwrap(); + let result = fit_in_memory::(usize::MAX, &mut bitmap, 128, &mut rng).unwrap(); + assert_eq!(result.len(), 100); + assert!(bitmap.is_empty()); +} + +#[test] +fn test_less_items_than_dimensions() { + let mut rng = StdRng::seed_from_u64(26); + let mut bitmap = RoaringBitmap::from_sorted_iter(0..10).unwrap(); + let result = fit_in_memory::(0, &mut bitmap, 128, &mut rng).unwrap(); + assert_eq!(result.len(), 10); + assert!(bitmap.is_empty()); +} + +#[test] +fn test_partial_fit() { + let mut rng = StdRng::seed_from_u64(3141592); + let mut bitmap = RoaringBitmap::from_sorted_iter(0..1000).unwrap(); + + let dimensions = 128; + let largest_item_size = Euclidean::size_of_item(dimensions); + let memory = largest_item_size * 500; + + let result = fit_in_memory::(memory, &mut bitmap, dimensions, &mut rng).unwrap(); + // We can't assert properly on the len of the result because the page_size vary depending on the system + assert!(result.len() > dimensions as u64); + assert_eq!(1000, bitmap.len() + result.len()); +} + +#[test] +fn test_random_selection() { + let mut rng = StdRng::seed_from_u64(24); + let bitmap = RoaringBitmap::from_sorted_iter(0..1000).unwrap(); + + let dimensions = 128; + let largest_item_size = Euclidean::size_of_item(dimensions); + let memory = largest_item_size * 500; + + // Get first batch + let mut bitmap_clone = bitmap.clone(); + let result1 = fit_in_memory::(memory, &mut bitmap_clone, dimensions, &mut rng).unwrap(); + assert!(result1.len() > dimensions as u64); + assert_eq!(1000, bitmap_clone.len() + result1.len()); + + // Get second batch + let mut bitmap_clone = bitmap.clone(); + let result2 = fit_in_memory::(memory, &mut bitmap_clone, dimensions, &mut rng).unwrap(); + assert!(result2.len() > dimensions as u64); + assert_eq!(1000, bitmap_clone.len() + result2.len()); + + // Batch must be different because of random selection but they must contains the same number of items + assert_eq!(result1.len(), result2.len()); + assert_ne!(result1, result2); +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index a0b0efd..69c88f7 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -16,6 +16,7 @@ mod reader; mod tmp_nodes; mod upgrade; mod writer; +mod fit_in_memory; pub struct DatabaseHandle { pub env: Env, diff --git a/src/writer.rs b/src/writer.rs index 7badd6e..03bcfa2 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1448,7 +1448,7 @@ fn insert_items_in_descendants_from_tmpfile( /// Returns the items from the `to_insert` that fit in memory. /// If there is no items to insert anymore, returns `None`. /// If everything fits in memory, returns the `to_insert` bitmap. -fn fit_in_memory( +pub(crate) fn fit_in_memory( memory: usize, to_insert: &mut RoaringBitmap, dimensions: usize, @@ -1478,6 +1478,15 @@ fn fit_in_memory( nb_page_allowed }; + dbg!(&nb_items); + + // We must insert at least dimensions items to create a split + let nb_items = if nb_items < dimensions { + dimensions + } else { + nb_items + }; + if nb_items as u64 >= to_insert.len() { return Some(std::mem::take(to_insert)); } @@ -1488,7 +1497,7 @@ fn fit_in_memory( let idx = rng.gen_range(0..to_insert.len()); // Safe to unwrap because we know nb_items is smaller than the number of items in the bitmap let item = to_insert.select(idx as u32).unwrap(); - items.push(item); + items.insert(item); to_insert.remove(item); } From 3a94056d269f49f0aa48f88309418a057d4c42d5 Mon Sep 17 00:00:00 2001 From: Tamo Date: Tue, 17 Jun 2025 17:34:47 +0200 Subject: [PATCH 21/24] Add a large test with no memory to force the full indexing process to run --- ...of_random_points_with_little_memory-2.snap | 567 ++++++++++++++++++ ...t_of_random_points_with_little_memory.snap | 296 +++++++++ src/tests/writer.rs | 28 + src/writer.rs | 4 +- 4 files changed, 893 insertions(+), 2 deletions(-) create mode 100644 src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points_with_little_memory-2.snap create mode 100644 src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points_with_little_memory.snap diff --git a/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points_with_little_memory-2.snap b/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points_with_little_memory-2.snap new file mode 100644 index 0000000..076d650 --- /dev/null +++ b/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points_with_little_memory-2.snap @@ -0,0 +1,567 @@ +--- +source: src/tests/writer.rs +expression: handle +--- +================== +Dumping index 0 +Root: Metadata { dimensions: 3, items: RoaringBitmap<150 values between 0 and 149>, roots: [0, 1, 188], distance: "cosine" } +Version: Version { major: 0, minor: 7, patch: 0 } +Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 94, right: 95, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.7419, -0.0092, 0.6705] } }) +Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 3, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.5938, 0.3404, -0.7290] } }) +Tree 2: SplitPlaneNormal(SplitPlaneNormal { left: 64, right: 65, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5969, 0.7955, -0.1042] } }) +Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6720, -0.7180, 0.1817] } }) +Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 42, right: 45, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8971, 0.4184, 0.1423] } }) +Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 6, right: 7, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.2091, -0.4533, 0.8665] } }) +Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 26, right: 27, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3881, 0.4833, 0.7847] } }) +Tree 7: SplitPlaneNormal(SplitPlaneNormal { left: 8, right: 9, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.0141, 0.8224, -0.5688] } }) +Tree 8: SplitPlaneNormal(SplitPlaneNormal { left: 16, right: 17, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6128, 0.7615, 0.2113] } }) +Tree 9: SplitPlaneNormal(SplitPlaneNormal { left: 10, right: 12, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7223, -0.6315, -0.2819] } }) +Tree 10: SplitPlaneNormal(SplitPlaneNormal { left: 473, right: 474, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.1805, -0.5812, 0.7935] } }) +Tree 12: Descendants(Descendants { descendants: [4, 59, 138] }) +Tree 16: SplitPlaneNormal(SplitPlaneNormal { left: 18, right: 19, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4400, -0.6017, -0.6666] } }) +Tree 17: SplitPlaneNormal(SplitPlaneNormal { left: 457, right: 458, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7648, -0.3201, -0.5591] } }) +Tree 18: SplitPlaneNormal(SplitPlaneNormal { left: 20, right: 21, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6356, -0.3787, -0.6728] } }) +Tree 19: SplitPlaneNormal(SplitPlaneNormal { left: 453, right: 454, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3880, -0.0274, -0.9212] } }) +Tree 20: SplitPlaneNormal(SplitPlaneNormal { left: 447, right: 448, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2480, -0.9656, 0.0777] } }) +Tree 21: Descendants(Descendants { descendants: [46, 75, 120] }) +Tree 26: SplitPlaneNormal(SplitPlaneNormal { left: 40, right: 41, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.1973, 0.9757, 0.0950] } }) +Tree 27: SplitPlaneNormal(SplitPlaneNormal { left: 28, right: 29, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6078, -0.7489, -0.2641] } }) +Tree 28: SplitPlaneNormal(SplitPlaneNormal { left: 34, right: 35, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6381, -0.4144, -0.6490] } }) +Tree 29: SplitPlaneNormal(SplitPlaneNormal { left: 433, right: 434, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3862, 0.9188, 0.0820] } }) +Tree 34: SplitPlaneNormal(SplitPlaneNormal { left: 36, right: 37, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7289, -0.4821, -0.4861] } }) +Tree 35: Descendants(Descendants { descendants: [19, 81, 118] }) +Tree 36: SplitPlaneNormal(SplitPlaneNormal { left: 413, right: 414, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.2625, -0.3008, 0.9169] } }) +Tree 37: SplitPlaneNormal(SplitPlaneNormal { left: 38, right: 39, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.4520, 0.7619, -0.4638] } }) +Tree 38: SplitPlaneNormal(SplitPlaneNormal { left: 405, right: 406, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2309, -0.7225, 0.6517] } }) +Tree 39: Descendants(Descendants { descendants: [45, 71] }) +Tree 40: SplitPlaneNormal(SplitPlaneNormal { left: 403, right: 404, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.1757, 0.8241, 0.5385] } }) +Tree 41: SplitPlaneNormal(SplitPlaneNormal { left: 395, right: 396, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3164, -0.9406, 0.1233] } }) +Tree 42: SplitPlaneNormal(SplitPlaneNormal { left: 52, right: 53, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.1610, 0.3819, -0.9101] } }) +Tree 45: SplitPlaneNormal(SplitPlaneNormal { left: 46, right: 47, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1491, 0.5140, -0.8448] } }) +Tree 46: Descendants(Descendants { descendants: [49, 91] }) +Tree 47: SplitPlaneNormal(SplitPlaneNormal { left: 48, right: 49, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.8454, -0.4542, 0.2812] } }) +Tree 48: SplitPlaneNormal(SplitPlaneNormal { left: 375, right: 376, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4911, -0.2623, 0.8307] } }) +Tree 49: Descendants(Descendants { descendants: [13, 23, 140] }) +Tree 52: SplitPlaneNormal(SplitPlaneNormal { left: 341, right: 342, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.5599, 0.1200, -0.8199] } }) +Tree 53: SplitPlaneNormal(SplitPlaneNormal { left: 335, right: 336, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.7792, 0.5645, 0.2723] } }) +Tree 64: SplitPlaneNormal(SplitPlaneNormal { left: 80, right: 84, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7926, -0.2856, -0.5388] } }) +Tree 65: SplitPlaneNormal(SplitPlaneNormal { left: 66, right: 72, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.0680, 0.7454, -0.6632] } }) +Tree 66: SplitPlaneNormal(SplitPlaneNormal { left: 493, right: 494, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2240, 0.8675, -0.4442] } }) +Tree 72: SplitPlaneNormal(SplitPlaneNormal { left: 479, right: 480, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.9140, -0.3803, 0.1412] } }) +Tree 80: SplitPlaneNormal(SplitPlaneNormal { left: 88, right: 89, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4346, 0.7756, -0.4578] } }) +Tree 84: SplitPlaneNormal(SplitPlaneNormal { left: 443, right: 444, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4369, -0.8596, -0.2651] } }) +Tree 88: SplitPlaneNormal(SplitPlaneNormal { left: 90, right: 91, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.9628, -0.0719, 0.2605] } }) +Tree 89: SplitPlaneNormal(SplitPlaneNormal { left: 441, right: 442, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7235, 0.4241, -0.5447] } }) +Tree 90: SplitPlaneNormal(SplitPlaneNormal { left: 92, right: 93, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8021, 0.4808, 0.3542] } }) +Tree 91: Descendants(Descendants { descendants: [55, 109, 147] }) +Tree 92: SplitPlaneNormal(SplitPlaneNormal { left: 439, right: 440, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2673, 0.9257, -0.2676] } }) +Tree 93: Descendants(Descendants { descendants: [37, 51] }) +Tree 94: SplitPlaneNormal(SplitPlaneNormal { left: 128, right: 129, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4785, -0.8779, -0.0195] } }) +Tree 95: SplitPlaneNormal(SplitPlaneNormal { left: 96, right: 97, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.9268, -0.3400, -0.1595] } }) +Tree 96: SplitPlaneNormal(SplitPlaneNormal { left: 114, right: 115, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.0640, 0.8356, -0.5456] } }) +Tree 97: SplitPlaneNormal(SplitPlaneNormal { left: 98, right: 100, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1260, 0.8927, -0.4327] } }) +Tree 98: SplitPlaneNormal(SplitPlaneNormal { left: 108, right: 109, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3363, -0.8669, 0.3680] } }) +Tree 100: SplitPlaneNormal(SplitPlaneNormal { left: 407, right: 408, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3952, -0.6037, 0.6924] } }) +Tree 108: SplitPlaneNormal(SplitPlaneNormal { left: 389, right: 390, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.8002, -0.4737, -0.3679] } }) +Tree 109: SplitPlaneNormal(SplitPlaneNormal { left: 110, right: 111, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8863, -0.1858, 0.4241] } }) +Tree 110: SplitPlaneNormal(SplitPlaneNormal { left: 387, right: 388, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.8246, -0.3603, -0.4361] } }) +Tree 111: Descendants(Descendants { descendants: [37] }) +Tree 114: SplitPlaneNormal(SplitPlaneNormal { left: 363, right: 364, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2172, 0.8988, -0.3807] } }) +Tree 115: SplitPlaneNormal(SplitPlaneNormal { left: 116, right: 117, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.4503, 0.5907, -0.6696] } }) +Tree 116: SplitPlaneNormal(SplitPlaneNormal { left: 353, right: 354, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7613, -0.5632, 0.3214] } }) +Tree 117: SplitPlaneNormal(SplitPlaneNormal { left: 345, right: 346, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3455, 0.2540, -0.9034] } }) +Tree 128: SplitPlaneNormal(SplitPlaneNormal { left: 152, right: 153, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6325, 0.7077, -0.3149] } }) +Tree 129: SplitPlaneNormal(SplitPlaneNormal { left: 130, right: 131, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3229, 0.5291, -0.7847] } }) +Tree 130: SplitPlaneNormal(SplitPlaneNormal { left: 140, right: 141, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5718, -0.3132, 0.7583] } }) +Tree 131: SplitPlaneNormal(SplitPlaneNormal { left: 137, right: 134, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.0720, -0.5319, 0.8437] } }) +Tree 134: SplitPlaneNormal(SplitPlaneNormal { left: 487, right: 488, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4324, -0.7417, -0.5127] } }) +Tree 137: SplitPlaneNormal(SplitPlaneNormal { left: 138, right: 139, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.2183, 0.8233, 0.5240] } }) +Tree 138: Descendants(Descendants { descendants: [5, 27, 77] }) +Tree 139: SplitPlaneNormal(SplitPlaneNormal { left: 467, right: 468, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2398, -0.8384, 0.4896] } }) +Tree 140: SplitPlaneNormal(SplitPlaneNormal { left: 461, right: 462, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5080, 0.7989, 0.3219] } }) +Tree 141: SplitPlaneNormal(SplitPlaneNormal { left: 142, right: 143, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1645, -0.9636, 0.2109] } }) +Tree 142: Descendants(Descendants { descendants: [10, 87] }) +Tree 143: SplitPlaneNormal(SplitPlaneNormal { left: 144, right: 145, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.0415, 0.9886, -0.1449] } }) +Tree 144: SplitPlaneNormal(SplitPlaneNormal { left: 459, right: 460, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6675, -0.1477, 0.7298] } }) +Tree 145: Descendants(Descendants { descendants: [38, 93, 133] }) +Tree 152: SplitPlaneNormal(SplitPlaneNormal { left: 166, right: 167, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.1407, 0.7156, -0.6842] } }) +Tree 153: SplitPlaneNormal(SplitPlaneNormal { left: 160, right: 159, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.5494, -0.1561, -0.8208] } }) +Tree 159: SplitPlaneNormal(SplitPlaneNormal { left: 429, right: 430, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6129, 0.5604, -0.5571] } }) +Tree 160: SplitPlaneNormal(SplitPlaneNormal { left: 419, right: 420, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6269, -0.5350, 0.5664] } }) +Tree 166: SplitPlaneNormal(SplitPlaneNormal { left: 178, right: 180, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6048, -0.0853, 0.7918] } }) +Tree 167: SplitPlaneNormal(SplitPlaneNormal { left: 168, right: 169, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6431, -0.6135, -0.4582] } }) +Tree 168: SplitPlaneNormal(SplitPlaneNormal { left: 170, right: 171, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6919, -0.1450, -0.7073] } }) +Tree 169: SplitPlaneNormal(SplitPlaneNormal { left: 399, right: 400, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1544, -0.4894, 0.8583] } }) +Tree 170: Descendants(Descendants { descendants: [85, 135] }) +Tree 171: SplitPlaneNormal(SplitPlaneNormal { left: 172, right: 173, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4012, 0.1846, -0.8972] } }) +Tree 172: SplitPlaneNormal(SplitPlaneNormal { left: 391, right: 392, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.0946, -0.6360, 0.7658] } }) +Tree 173: SplitPlaneNormal(SplitPlaneNormal { left: 174, right: 175, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6930, -0.7206, -0.0238] } }) +Tree 174: SplitPlaneNormal(SplitPlaneNormal { left: 385, right: 386, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7429, -0.4517, -0.4941] } }) +Tree 175: Descendants(Descendants { descendants: [57, 69] }) +Tree 178: SplitPlaneNormal(SplitPlaneNormal { left: 371, right: 372, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6954, -0.3130, -0.6469] } }) +Tree 180: SplitPlaneNormal(SplitPlaneNormal { left: 329, right: 330, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.1684, 0.8359, -0.5224] } }) +Tree 188: SplitPlaneNormal(SplitPlaneNormal { left: 189, right: 190, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3588, 0.9273, -0.1069] } }) +Tree 189: SplitPlaneNormal(SplitPlaneNormal { left: 287, right: 288, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.4411, -0.2194, 0.8702] } }) +Tree 190: SplitPlaneNormal(SplitPlaneNormal { left: 191, right: 192, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4813, 0.4888, -0.7276] } }) +Tree 191: SplitPlaneNormal(SplitPlaneNormal { left: 193, right: 194, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1905, 0.8307, -0.5231] } }) +Tree 192: SplitPlaneNormal(SplitPlaneNormal { left: 219, right: 220, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5020, 0.0420, 0.8639] } }) +Tree 193: SplitPlaneNormal(SplitPlaneNormal { left: 213, right: 214, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.9237, 0.1519, -0.3517] } }) +Tree 194: SplitPlaneNormal(SplitPlaneNormal { left: 195, right: 196, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5054, 0.6634, -0.5519] } }) +Tree 195: SplitPlaneNormal(SplitPlaneNormal { left: 197, right: 198, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.0960, 0.8217, -0.5618] } }) +Tree 196: SplitPlaneNormal(SplitPlaneNormal { left: 209, right: 210, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4870, 0.5360, -0.6896] } }) +Tree 197: SplitPlaneNormal(SplitPlaneNormal { left: 205, right: 206, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.9733, 0.1535, 0.1707] } }) +Tree 198: SplitPlaneNormal(SplitPlaneNormal { left: 199, right: 200, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.9474, -0.2820, -0.1513] } }) +Tree 199: SplitPlaneNormal(SplitPlaneNormal { left: 201, right: 202, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.9048, -0.1897, 0.3813] } }) +Tree 200: SplitPlaneNormal(SplitPlaneNormal { left: 203, right: 204, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1717, -0.7823, 0.5988] } }) +Tree 201: Descendants(Descendants { descendants: [8, 106, 130] }) +Tree 202: Descendants(Descendants { descendants: [22, 134] }) +Tree 203: Descendants(Descendants { descendants: [137] }) +Tree 204: Descendants(Descendants { descendants: [26, 56, 121] }) +Tree 205: Descendants(Descendants { descendants: [58, 79] }) +Tree 206: SplitPlaneNormal(SplitPlaneNormal { left: 207, right: 208, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6205, 0.5886, -0.5183] } }) +Tree 207: Descendants(Descendants { descendants: [3, 24, 76] }) +Tree 208: Descendants(Descendants { descendants: [149] }) +Tree 209: SplitPlaneNormal(SplitPlaneNormal { left: 211, right: 212, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.9497, 0.1519, -0.2738] } }) +Tree 210: Descendants(Descendants { descendants: [104] }) +Tree 211: Descendants(Descendants { descendants: [40, 103] }) +Tree 212: Descendants(Descendants { descendants: [14, 136] }) +Tree 213: SplitPlaneNormal(SplitPlaneNormal { left: 217, right: 218, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.4724, 0.8516, -0.2274] } }) +Tree 214: SplitPlaneNormal(SplitPlaneNormal { left: 215, right: 216, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.4389, -0.7273, 0.5277] } }) +Tree 215: Descendants(Descendants { descendants: [7, 28] }) +Tree 216: Descendants(Descendants { descendants: [53, 127] }) +Tree 217: Descendants(Descendants { descendants: [55, 82, 148] }) +Tree 218: Descendants(Descendants { descendants: [43, 68] }) +Tree 219: SplitPlaneNormal(SplitPlaneNormal { left: 221, right: 222, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6571, -0.7532, 0.0308] } }) +Tree 220: SplitPlaneNormal(SplitPlaneNormal { left: 243, right: 244, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6584, -0.4453, 0.6068] } }) +Tree 221: SplitPlaneNormal(SplitPlaneNormal { left: 233, right: 234, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8660, 0.4999, -0.0087] } }) +Tree 222: SplitPlaneNormal(SplitPlaneNormal { left: 223, right: 224, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1999, -0.0850, -0.9761] } }) +Tree 223: SplitPlaneNormal(SplitPlaneNormal { left: 225, right: 226, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.0333, -0.5051, 0.8624] } }) +Tree 224: Descendants(Descendants { descendants: [19, 61] }) +Tree 225: SplitPlaneNormal(SplitPlaneNormal { left: 231, right: 232, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.2287, 0.0044, 0.9735] } }) +Tree 226: SplitPlaneNormal(SplitPlaneNormal { left: 227, right: 228, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5883, 0.7959, 0.1430] } }) +Tree 227: SplitPlaneNormal(SplitPlaneNormal { left: 229, right: 230, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.2436, -0.1970, 0.9497] } }) +Tree 228: Descendants(Descendants { descendants: [57] }) +Tree 229: Descendants(Descendants { descendants: [34, 90] }) +Tree 230: Descendants(Descendants { descendants: [113, 125] }) +Tree 231: Descendants(Descendants { descendants: [101, 141] }) +Tree 232: Descendants(Descendants { descendants: [1, 81] }) +Tree 233: SplitPlaneNormal(SplitPlaneNormal { left: 235, right: 236, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3358, -0.0493, -0.9406] } }) +Tree 234: Descendants(Descendants { descendants: [6] }) +Tree 235: SplitPlaneNormal(SplitPlaneNormal { left: 237, right: 238, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6166, -0.6852, 0.3878] } }) +Tree 236: SplitPlaneNormal(SplitPlaneNormal { left: 239, right: 240, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.7724, 0.5675, 0.2853] } }) +Tree 237: Descendants(Descendants { descendants: [117, 128] }) +Tree 238: Descendants(Descendants { descendants: [45, 71] }) +Tree 239: SplitPlaneNormal(SplitPlaneNormal { left: 241, right: 242, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3038, -0.3798, 0.8738] } }) +Tree 240: Descendants(Descendants { descendants: [65] }) +Tree 241: Descendants(Descendants { descendants: [36, 97] }) +Tree 242: Descendants(Descendants { descendants: [30, 124, 143] }) +Tree 243: SplitPlaneNormal(SplitPlaneNormal { left: 245, right: 246, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.4678, -0.2194, 0.8562] } }) +Tree 244: SplitPlaneNormal(SplitPlaneNormal { left: 251, right: 252, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1438, 0.4183, -0.8968] } }) +Tree 245: SplitPlaneNormal(SplitPlaneNormal { left: 249, right: 250, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8382, 0.2362, -0.4916] } }) +Tree 246: SplitPlaneNormal(SplitPlaneNormal { left: 247, right: 248, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8161, -0.1328, 0.5625] } }) +Tree 247: Descendants(Descendants { descendants: [83, 84, 116] }) +Tree 248: Descendants(Descendants { descendants: [50] }) +Tree 249: Descendants(Descendants { descendants: [72, 74, 92] }) +Tree 250: Descendants(Descendants { descendants: [12, 105] }) +Tree 251: SplitPlaneNormal(SplitPlaneNormal { left: 253, right: 254, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.2413, -0.5591, 0.7932] } }) +Tree 252: SplitPlaneNormal(SplitPlaneNormal { left: 283, right: 284, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8495, 0.5177, -0.1022] } }) +Tree 253: SplitPlaneNormal(SplitPlaneNormal { left: 261, right: 262, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.8814, -0.4628, -0.0949] } }) +Tree 254: SplitPlaneNormal(SplitPlaneNormal { left: 255, right: 256, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.7387, 0.6726, 0.0441] } }) +Tree 255: SplitPlaneNormal(SplitPlaneNormal { left: 257, right: 258, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3479, 0.8960, -0.2758] } }) +Tree 256: Descendants(Descendants { descendants: [0, 91, 119] }) +Tree 257: SplitPlaneNormal(SplitPlaneNormal { left: 259, right: 260, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6173, 0.1505, -0.7722] } }) +Tree 258: Descendants(Descendants { descendants: [9, 48, 70] }) +Tree 259: Descendants(Descendants { descendants: [20, 29, 98] }) +Tree 260: Descendants(Descendants { descendants: [4, 54, 59] }) +Tree 261: SplitPlaneNormal(SplitPlaneNormal { left: 279, right: 280, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.9326, 0.3602, -0.0232] } }) +Tree 262: SplitPlaneNormal(SplitPlaneNormal { left: 263, right: 264, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7109, -0.1362, -0.6900] } }) +Tree 263: Descendants(Descendants { descendants: [44, 85] }) +Tree 264: SplitPlaneNormal(SplitPlaneNormal { left: 265, right: 266, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6672, 0.7372, 0.1067] } }) +Tree 265: SplitPlaneNormal(SplitPlaneNormal { left: 275, right: 276, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3336, -0.8868, 0.3197] } }) +Tree 266: SplitPlaneNormal(SplitPlaneNormal { left: 267, right: 268, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.1407, 0.6579, -0.7399] } }) +Tree 267: SplitPlaneNormal(SplitPlaneNormal { left: 269, right: 270, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4655, 0.1595, -0.8706] } }) +Tree 268: Descendants(Descendants { descendants: [114, 126] }) +Tree 269: SplitPlaneNormal(SplitPlaneNormal { left: 271, right: 272, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5039, 0.7948, -0.3383] } }) +Tree 270: Descendants(Descendants { descendants: [33] }) +Tree 271: Descendants(Descendants { descendants: [21, 39] }) +Tree 272: SplitPlaneNormal(SplitPlaneNormal { left: 273, right: 274, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1299, 0.5124, -0.8489] } }) +Tree 273: Descendants(Descendants { descendants: [99, 123, 135] }) +Tree 274: Descendants(Descendants { descendants: [66, 142] }) +Tree 275: SplitPlaneNormal(SplitPlaneNormal { left: 277, right: 278, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4732, -0.8507, 0.2291] } }) +Tree 276: Descendants(Descendants { descendants: [138] }) +Tree 277: Descendants(Descendants { descendants: [69, 100, 145] }) +Tree 278: Descendants(Descendants { descendants: [118] }) +Tree 279: SplitPlaneNormal(SplitPlaneNormal { left: 281, right: 282, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7038, 0.1428, -0.6959] } }) +Tree 280: Descendants(Descendants { descendants: [25, 139, 146] }) +Tree 281: Descendants(Descendants { descendants: [49, 111] }) +Tree 282: Descendants(Descendants { descendants: [13, 52] }) +Tree 283: SplitPlaneNormal(SplitPlaneNormal { left: 285, right: 286, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.7841, 0.6195, -0.0365] } }) +Tree 284: Descendants(Descendants { descendants: [23, 41, 140] }) +Tree 285: Descendants(Descendants { descendants: [31, 112] }) +Tree 286: Descendants(Descendants { descendants: [78, 96] }) +Tree 287: SplitPlaneNormal(SplitPlaneNormal { left: 289, right: 290, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1124, 0.6347, -0.7645] } }) +Tree 288: SplitPlaneNormal(SplitPlaneNormal { left: 303, right: 304, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.8003, 0.2595, -0.5406] } }) +Tree 289: SplitPlaneNormal(SplitPlaneNormal { left: 299, right: 300, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3454, 0.6185, 0.7058] } }) +Tree 290: SplitPlaneNormal(SplitPlaneNormal { left: 291, right: 292, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3311, -0.5678, -0.7536] } }) +Tree 291: Descendants(Descendants { descendants: [15, 42] }) +Tree 292: SplitPlaneNormal(SplitPlaneNormal { left: 293, right: 294, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2595, -0.9487, -0.1805] } }) +Tree 293: SplitPlaneNormal(SplitPlaneNormal { left: 297, right: 298, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2025, -0.8428, 0.4986] } }) +Tree 294: SplitPlaneNormal(SplitPlaneNormal { left: 295, right: 296, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1648, -0.9419, -0.2926] } }) +Tree 295: Descendants(Descendants { descendants: [27, 132, 144] }) +Tree 296: Descendants(Descendants { descendants: [5, 77] }) +Tree 297: Descendants(Descendants { descendants: [17, 60] }) +Tree 298: Descendants(Descendants { descendants: [18, 47, 86] }) +Tree 299: SplitPlaneNormal(SplitPlaneNormal { left: 301, right: 302, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.2957, -0.4370, 0.8495] } }) +Tree 300: Descendants(Descendants { descendants: [64, 110, 122] }) +Tree 301: Descendants(Descendants { descendants: [108, 131] }) +Tree 302: Descendants(Descendants { descendants: [11, 80] }) +Tree 303: SplitPlaneNormal(SplitPlaneNormal { left: 305, right: 306, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8935, 0.2904, 0.3426] } }) +Tree 304: SplitPlaneNormal(SplitPlaneNormal { left: 309, right: 310, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4390, -0.8720, -0.2164] } }) +Tree 305: SplitPlaneNormal(SplitPlaneNormal { left: 307, right: 308, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5735, 0.7820, 0.2440] } }) +Tree 306: Descendants(Descendants { descendants: [37, 109, 147] }) +Tree 307: Descendants(Descendants { descendants: [73, 95] }) +Tree 308: Descendants(Descendants { descendants: [51, 62] }) +Tree 309: SplitPlaneNormal(SplitPlaneNormal { left: 321, right: 322, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.4056, -0.6411, 0.6515] } }) +Tree 310: SplitPlaneNormal(SplitPlaneNormal { left: 311, right: 312, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3626, 0.7425, -0.5632] } }) +Tree 311: SplitPlaneNormal(SplitPlaneNormal { left: 313, right: 314, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6511, -0.3522, -0.6723] } }) +Tree 312: SplitPlaneNormal(SplitPlaneNormal { left: 317, right: 318, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4850, -0.5652, -0.6674] } }) +Tree 313: Descendants(Descendants { descendants: [67] }) +Tree 314: SplitPlaneNormal(SplitPlaneNormal { left: 315, right: 316, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.5180, 0.6032, -0.6065] } }) +Tree 315: Descendants(Descendants { descendants: [32, 35] }) +Tree 316: Descendants(Descendants { descendants: [88, 89] }) +Tree 317: SplitPlaneNormal(SplitPlaneNormal { left: 319, right: 320, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.4502, -0.5103, 0.7327] } }) +Tree 318: Descendants(Descendants { descendants: [115] }) +Tree 319: Descendants(Descendants { descendants: [46, 75] }) +Tree 320: Descendants(Descendants { descendants: [38, 120] }) +Tree 321: SplitPlaneNormal(SplitPlaneNormal { left: 325, right: 326, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6008, 0.1985, -0.7743] } }) +Tree 322: SplitPlaneNormal(SplitPlaneNormal { left: 323, right: 324, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6741, 0.3535, -0.6486] } }) +Tree 323: Descendants(Descendants { descendants: [102, 129] }) +Tree 324: Descendants(Descendants { descendants: [16, 93, 133] }) +Tree 325: SplitPlaneNormal(SplitPlaneNormal { left: 327, right: 328, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.2242, -0.7741, 0.5920] } }) +Tree 326: Descendants(Descendants { descendants: [63, 94] }) +Tree 327: Descendants(Descendants { descendants: [2, 87, 107] }) +Tree 328: Descendants(Descendants { descendants: [10] }) +Tree 329: SplitPlaneNormal(SplitPlaneNormal { left: 331, right: 332, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.5918, -0.8057, -0.0251] } }) +Tree 330: Descendants(Descendants { descendants: [44, 48, 70] }) +Tree 331: Descendants(Descendants { descendants: [9] }) +Tree 332: SplitPlaneNormal(SplitPlaneNormal { left: 333, right: 334, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7703, -0.3282, -0.5468] } }) +Tree 333: Descendants(Descendants { descendants: [29] }) +Tree 334: Descendants(Descendants { descendants: [20, 54, 98] }) +Tree 335: SplitPlaneNormal(SplitPlaneNormal { left: 337, right: 338, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2529, -0.0839, -0.9638] } }) +Tree 336: Descendants(Descendants { descendants: [65] }) +Tree 337: Descendants(Descendants { descendants: [30] }) +Tree 338: SplitPlaneNormal(SplitPlaneNormal { left: 339, right: 340, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6012, 0.4896, 0.6315] } }) +Tree 339: Descendants(Descendants { descendants: [36, 143] }) +Tree 340: Descendants(Descendants { descendants: [97, 124] }) +Tree 341: Descendants(Descendants { descendants: [0, 52, 85] }) +Tree 342: SplitPlaneNormal(SplitPlaneNormal { left: 343, right: 344, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7599, -0.6195, 0.1971] } }) +Tree 343: Descendants(Descendants { descendants: [96, 117] }) +Tree 344: Descendants(Descendants { descendants: [31, 78, 128] }) +Tree 345: SplitPlaneNormal(SplitPlaneNormal { left: 347, right: 348, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7789, 0.1483, -0.6094] } }) +Tree 346: Descendants(Descendants { descendants: [105] }) +Tree 347: Descendants(Descendants { descendants: [25, 50] }) +Tree 348: SplitPlaneNormal(SplitPlaneNormal { left: 349, right: 350, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.2266, 0.3561, -0.9066] } }) +Tree 349: SplitPlaneNormal(SplitPlaneNormal { left: 351, right: 352, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.0382, 0.4334, -0.9004] } }) +Tree 350: Descendants(Descendants { descendants: [74] }) +Tree 351: Descendants(Descendants { descendants: [139] }) +Tree 352: Descendants(Descendants { descendants: [83, 84, 116] }) +Tree 353: SplitPlaneNormal(SplitPlaneNormal { left: 359, right: 360, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.7709, -0.3440, 0.5361] } }) +Tree 354: SplitPlaneNormal(SplitPlaneNormal { left: 355, right: 356, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1993, 0.6683, -0.7167] } }) +Tree 355: SplitPlaneNormal(SplitPlaneNormal { left: 357, right: 358, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.2637, -0.7109, 0.6520] } }) +Tree 356: Descendants(Descendants { descendants: [49, 111, 137] }) +Tree 357: Descendants(Descendants { descendants: [56, 106, 130] }) +Tree 358: Descendants(Descendants { descendants: [3, 8, 149] }) +Tree 359: Descendants(Descendants { descendants: [14, 104, 146] }) +Tree 360: SplitPlaneNormal(SplitPlaneNormal { left: 361, right: 362, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.8255, -0.4591, 0.3283] } }) +Tree 361: Descendants(Descendants { descendants: [40, 103, 136] }) +Tree 362: Descendants(Descendants { descendants: [22, 134] }) +Tree 363: SplitPlaneNormal(SplitPlaneNormal { left: 365, right: 366, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.0431, -0.9825, 0.1814] } }) +Tree 364: SplitPlaneNormal(SplitPlaneNormal { left: 369, right: 370, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.5787, 0.6873, -0.4390] } }) +Tree 365: SplitPlaneNormal(SplitPlaneNormal { left: 367, right: 368, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6171, 0.7767, -0.1258] } }) +Tree 366: Descendants(Descendants { descendants: [109, 147] }) +Tree 367: Descendants(Descendants { descendants: [55, 82, 148] }) +Tree 368: Descendants(Descendants { descendants: [43] }) +Tree 369: Descendants(Descendants { descendants: [68] }) +Tree 370: Descendants(Descendants { descendants: [24, 76, 79] }) +Tree 371: SplitPlaneNormal(SplitPlaneNormal { left: 373, right: 374, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3818, 0.8672, -0.3198] } }) +Tree 372: Descendants(Descendants { descendants: [100, 118, 145] }) +Tree 373: Descendants(Descendants { descendants: [4, 59] }) +Tree 374: Descendants(Descendants { descendants: [21, 39] }) +Tree 375: Descendants(Descendants { descendants: [6, 12, 105] }) +Tree 376: SplitPlaneNormal(SplitPlaneNormal { left: 377, right: 378, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8947, -0.0131, 0.4465] } }) +Tree 377: SplitPlaneNormal(SplitPlaneNormal { left: 379, right: 380, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.7897, 0.0893, 0.6069] } }) +Tree 378: Descendants(Descendants { descendants: [50] }) +Tree 379: Descendants(Descendants { descendants: [72] }) +Tree 380: SplitPlaneNormal(SplitPlaneNormal { left: 381, right: 382, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3953, 0.2039, -0.8956] } }) +Tree 381: SplitPlaneNormal(SplitPlaneNormal { left: 383, right: 384, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2688, -0.4681, 0.8418] } }) +Tree 382: Descendants(Descendants { descendants: [41, 74, 92] }) +Tree 383: Descendants(Descendants { descendants: [83, 84, 116] }) +Tree 384: Descendants(Descendants { descendants: [139] }) +Tree 385: Descendants(Descendants { descendants: [31, 112] }) +Tree 386: Descendants(Descendants { descendants: [45, 71] }) +Tree 387: Descendants(Descendants { descendants: [51, 62] }) +Tree 388: Descendants(Descendants { descendants: [73, 95, 102] }) +Tree 389: Descendants(Descendants { descendants: [53, 127] }) +Tree 390: Descendants(Descendants { descendants: [16, 129] }) +Tree 391: Descendants(Descendants { descendants: [33, 114, 126] }) +Tree 392: SplitPlaneNormal(SplitPlaneNormal { left: 393, right: 394, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1930, -0.7028, 0.6847] } }) +Tree 393: Descendants(Descendants { descendants: [66] }) +Tree 394: Descendants(Descendants { descendants: [99, 123, 142] }) +Tree 395: Descendants(Descendants { descendants: [60, 61] }) +Tree 396: SplitPlaneNormal(SplitPlaneNormal { left: 397, right: 398, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2317, -0.3972, -0.8880] } }) +Tree 397: Descendants(Descendants { descendants: [18, 47, 86] }) +Tree 398: Descendants(Descendants { descendants: [17, 132] }) +Tree 399: Descendants(Descendants { descendants: [19, 141] }) +Tree 400: SplitPlaneNormal(SplitPlaneNormal { left: 401, right: 402, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.0266, 0.3570, -0.9337] } }) +Tree 401: Descendants(Descendants { descendants: [1, 34] }) +Tree 402: Descendants(Descendants { descendants: [81, 101] }) +Tree 403: Descendants(Descendants { descendants: [5, 77] }) +Tree 404: Descendants(Descendants { descendants: [27, 144] }) +Tree 405: Descendants(Descendants { descendants: [57] }) +Tree 406: Descendants(Descendants { descendants: [69, 100, 145] }) +Tree 407: SplitPlaneNormal(SplitPlaneNormal { left: 409, right: 410, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3772, 0.5230, -0.7644] } }) +Tree 408: Descendants(Descendants { descendants: [7, 28, 58] }) +Tree 409: Descendants(Descendants { descendants: [26, 121] }) +Tree 410: SplitPlaneNormal(SplitPlaneNormal { left: 411, right: 412, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7612, -0.6355, 0.1293] } }) +Tree 411: Descendants(Descendants { descendants: [52, 91] }) +Tree 412: Descendants(Descendants { descendants: [0, 119] }) +Tree 413: Descendants(Descendants { descendants: [112] }) +Tree 414: SplitPlaneNormal(SplitPlaneNormal { left: 415, right: 416, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.1601, 0.6635, -0.7308] } }) +Tree 415: SplitPlaneNormal(SplitPlaneNormal { left: 417, right: 418, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.0057, 0.5858, -0.8104] } }) +Tree 416: Descendants(Descendants { descendants: [114, 126] }) +Tree 417: Descendants(Descendants { descendants: [99, 142] }) +Tree 418: Descendants(Descendants { descendants: [33, 66] }) +Tree 419: SplitPlaneNormal(SplitPlaneNormal { left: 421, right: 422, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8259, 0.2847, -0.4867] } }) +Tree 420: SplitPlaneNormal(SplitPlaneNormal { left: 425, right: 426, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5278, -0.0750, 0.8460] } }) +Tree 421: SplitPlaneNormal(SplitPlaneNormal { left: 423, right: 424, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7425, -0.1049, -0.6616] } }) +Tree 422: Descendants(Descendants { descendants: [6, 12] }) +Tree 423: Descendants(Descendants { descendants: [41, 92] }) +Tree 424: Descendants(Descendants { descendants: [72, 140] }) +Tree 425: SplitPlaneNormal(SplitPlaneNormal { left: 427, right: 428, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4267, 0.0742, -0.9014] } }) +Tree 426: Descendants(Descendants { descendants: [13, 23] }) +Tree 427: Descendants(Descendants { descendants: [78, 96] }) +Tree 428: Descendants(Descendants { descendants: [117, 128] }) +Tree 429: SplitPlaneNormal(SplitPlaneNormal { left: 431, right: 432, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2489, -0.0813, -0.9651] } }) +Tree 430: Descendants(Descendants { descendants: [65, 97] }) +Tree 431: Descendants(Descendants { descendants: [30] }) +Tree 432: Descendants(Descendants { descendants: [36, 124, 143] }) +Tree 433: Descendants(Descendants { descendants: [15, 42, 110] }) +Tree 434: SplitPlaneNormal(SplitPlaneNormal { left: 435, right: 436, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3958, -0.0632, -0.9161] } }) +Tree 435: Descendants(Descendants { descendants: [113, 125] }) +Tree 436: SplitPlaneNormal(SplitPlaneNormal { left: 437, right: 438, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1763, -0.5962, 0.7833] } }) +Tree 437: Descendants(Descendants { descendants: [101, 141] }) +Tree 438: Descendants(Descendants { descendants: [1, 34, 90] }) +Tree 439: Descendants(Descendants { descendants: [62, 73, 95] }) +Tree 440: Descendants(Descendants { descendants: [102, 129] }) +Tree 441: Descendants(Descendants { descendants: [127] }) +Tree 442: Descendants(Descendants { descendants: [7, 28, 53] }) +Tree 443: Descendants(Descendants { descendants: [16, 133] }) +Tree 444: SplitPlaneNormal(SplitPlaneNormal { left: 445, right: 446, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5886, -0.4567, 0.6670] } }) +Tree 445: Descendants(Descendants { descendants: [88, 89] }) +Tree 446: Descendants(Descendants { descendants: [32, 35, 67] }) +Tree 447: SplitPlaneNormal(SplitPlaneNormal { left: 449, right: 450, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5735, -0.2849, 0.7681] } }) +Tree 448: Descendants(Descendants { descendants: [38, 93] }) +Tree 449: Descendants(Descendants { descendants: [63, 94] }) +Tree 450: SplitPlaneNormal(SplitPlaneNormal { left: 451, right: 452, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3672, 0.6352, -0.6795] } }) +Tree 451: Descendants(Descendants { descendants: [10] }) +Tree 452: Descendants(Descendants { descendants: [2, 87, 107] }) +Tree 453: Descendants(Descendants { descendants: [11, 80, 115] }) +Tree 454: SplitPlaneNormal(SplitPlaneNormal { left: 455, right: 456, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3017, -0.7158, -0.6297] } }) +Tree 455: Descendants(Descendants { descendants: [64, 122] }) +Tree 456: Descendants(Descendants { descendants: [108, 131] }) +Tree 457: Descendants(Descendants { descendants: [29] }) +Tree 458: Descendants(Descendants { descendants: [20, 54, 98] }) +Tree 459: Descendants(Descendants { descendants: [88, 89] }) +Tree 460: Descendants(Descendants { descendants: [32, 35, 67] }) +Tree 461: SplitPlaneNormal(SplitPlaneNormal { left: 465, right: 466, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.4980, 0.3895, 0.7748] } }) +Tree 462: SplitPlaneNormal(SplitPlaneNormal { left: 463, right: 464, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5404, -0.3224, 0.7772] } }) +Tree 463: Descendants(Descendants { descendants: [63, 94] }) +Tree 464: Descendants(Descendants { descendants: [2, 107] }) +Tree 465: Descendants(Descendants { descendants: [11, 80, 115] }) +Tree 466: Descendants(Descendants { descendants: [46, 75, 120] }) +Tree 467: Descendants(Descendants { descendants: [60, 61, 90] }) +Tree 468: SplitPlaneNormal(SplitPlaneNormal { left: 469, right: 470, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1229, -0.8266, 0.5493] } }) +Tree 469: SplitPlaneNormal(SplitPlaneNormal { left: 471, right: 472, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3011, 0.4124, 0.8598] } }) +Tree 470: Descendants(Descendants { descendants: [47, 132, 144] }) +Tree 471: Descendants(Descendants { descendants: [17, 18, 86] }) +Tree 472: Descendants(Descendants { descendants: [42] }) +Tree 473: SplitPlaneNormal(SplitPlaneNormal { left: 477, right: 478, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.5029, -0.8060, 0.3122] } }) +Tree 474: SplitPlaneNormal(SplitPlaneNormal { left: 475, right: 476, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.7305, 0.6762, 0.0959] } }) +Tree 475: Descendants(Descendants { descendants: [9, 48] }) +Tree 476: Descendants(Descendants { descendants: [70, 119] }) +Tree 477: Descendants(Descendants { descendants: [44, 123, 135] }) +Tree 478: Descendants(Descendants { descendants: [21, 39] }) +Tree 479: SplitPlaneNormal(SplitPlaneNormal { left: 481, right: 482, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.8517, 0.2846, -0.4400] } }) +Tree 480: SplitPlaneNormal(SplitPlaneNormal { left: 483, right: 484, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.5694, -0.6826, 0.4581] } }) +Tree 481: Descendants(Descendants { descendants: [40, 103, 136] }) +Tree 482: Descendants(Descendants { descendants: [14, 25, 104] }) +Tree 483: Descendants(Descendants { descendants: [111, 146] }) +Tree 484: SplitPlaneNormal(SplitPlaneNormal { left: 485, right: 486, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.9397, 0.3209, 0.1184] } }) +Tree 485: Descendants(Descendants { descendants: [26, 121, 137] }) +Tree 486: Descendants(Descendants { descendants: [106, 130] }) +Tree 487: Descendants(Descendants { descendants: [113, 125, 138] }) +Tree 488: SplitPlaneNormal(SplitPlaneNormal { left: 489, right: 490, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2350, -0.9386, -0.2527] } }) +Tree 489: SplitPlaneNormal(SplitPlaneNormal { left: 491, right: 492, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.1033, 0.9496, -0.2960] } }) +Tree 490: Descendants(Descendants { descendants: [108, 131] }) +Tree 491: Descendants(Descendants { descendants: [64, 122] }) +Tree 492: Descendants(Descendants { descendants: [15, 110] }) +Tree 493: SplitPlaneNormal(SplitPlaneNormal { left: 501, right: 502, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4123, -0.8800, 0.2359] } }) +Tree 494: SplitPlaneNormal(SplitPlaneNormal { left: 495, right: 496, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.9377, -0.3459, 0.0330] } }) +Tree 495: SplitPlaneNormal(SplitPlaneNormal { left: 497, right: 498, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6086, -0.6856, 0.3994] } }) +Tree 496: SplitPlaneNormal(SplitPlaneNormal { left: 499, right: 500, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.0393, -0.8199, 0.5712] } }) +Tree 497: Descendants(Descendants { descendants: [22, 134] }) +Tree 498: Descendants(Descendants { descendants: [3, 24, 76] }) +Tree 499: Descendants(Descendants { descendants: [8, 56] }) +Tree 500: Descendants(Descendants { descendants: [58, 79, 149] }) +Tree 501: Descendants(Descendants { descendants: [43, 68] }) +Tree 502: Descendants(Descendants { descendants: [82, 148] }) +Item 0: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9249" }, vector: [0.4079, 0.5972, 0.5766] }) +Item 1: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0443" }, vector: [0.8606, 0.5280, 0.2667] }) +Item 2: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9610" }, vector: [0.6739, 0.2985, 0.6167] }) +Item 3: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.5378" }, vector: [0.0479, 0.2927, 0.4487] }) +Item 4: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.6832" }, vector: [0.4834, 0.2818, 0.3920] }) +Item 5: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7470" }, vector: [0.7418, 0.0595, 0.0652] }) +Item 6: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0038" }, vector: [0.2409, 0.9702, 0.0911] }) +Item 7: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.4776" }, vector: [0.2155, 0.1841, 0.3845] }) +Item 8: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1446" }, vector: [0.2453, 0.6558, 0.9055] }) +Item 9: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.5567" }, vector: [0.9152, 0.7847, 0.9849] }) +Item 10: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0765" }, vector: [0.7360, 0.3131, 0.7204] }) +Item 11: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9246" }, vector: [0.8414, 0.0192, 0.3828] }) +Item 12: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7468" }, vector: [0.0299, 0.7458, 0.0238] }) +Item 13: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1116" }, vector: [0.4624, 0.8739, 0.5080] }) +Item 14: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9879" }, vector: [0.1737, 0.7046, 0.6704] }) +Item 15: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.6977" }, vector: [0.6341, 0.1904, 0.2201] }) +Item 16: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3220" }, vector: [0.8351, 0.2749, 0.9873] }) +Item 17: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.6904" }, vector: [0.6554, 0.2088, 0.0586] }) +Item 18: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8414" }, vector: [0.7914, 0.2447, 0.1475] }) +Item 19: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2199" }, vector: [0.9246, 0.7944, 0.0473] }) +Item 20: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1741" }, vector: [0.7740, 0.4535, 0.7574] }) +Item 21: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8493" }, vector: [0.5344, 0.4903, 0.4420] }) +Item 22: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8526" }, vector: [0.0332, 0.5334, 0.6643] }) +Item 23: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7987" }, vector: [0.3315, 0.6684, 0.2849] }) +Item 24: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8138" }, vector: [0.1125, 0.4113, 0.6932] }) +Item 25: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9546" }, vector: [0.1173, 0.7807, 0.5366] }) +Item 26: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1688" }, vector: [0.4522, 0.7108, 0.8101] }) +Item 27: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.3820" }, vector: [0.3727, 0.0552, 0.0634] }) +Item 28: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9284" }, vector: [0.4659, 0.3048, 0.7430] }) +Item 29: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.4602" }, vector: [0.8893, 0.6025, 0.9890] }) +Item 30: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2877" }, vector: [0.8442, 0.9418, 0.2419] }) +Item 31: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7464" }, vector: [0.4568, 0.5250, 0.2701] }) +Item 32: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0318" }, vector: [0.7590, 0.0127, 0.6989] }) +Item 33: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3377" }, vector: [0.8759, 0.8323, 0.5742] }) +Item 34: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9270" }, vector: [0.7743, 0.4338, 0.2675] }) +Item 35: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8325" }, vector: [0.6038, 0.0168, 0.5729] }) +Item 36: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3546" }, vector: [0.9357, 0.9794, 0.0114] }) +Item 37: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9081" }, vector: [0.2978, 0.0910, 0.8530] }) +Item 38: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1584" }, vector: [0.8744, 0.1726, 0.7399] }) +Item 39: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7896" }, vector: [0.5211, 0.4583, 0.3767] }) +Item 40: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2339" }, vector: [0.0271, 0.8721, 0.8725] }) +Item 41: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9873" }, vector: [0.3022, 0.8817, 0.3255] }) +Item 42: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.4438" }, vector: [0.4023, 0.1558, 0.1044] }) +Item 43: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.6672" }, vector: [0.0860, 0.2202, 0.6240] }) +Item 44: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.3497" }, vector: [0.2096, 0.2081, 0.1872] }) +Item 45: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2019" }, vector: [0.8040, 0.7845, 0.4275] }) +Item 46: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.6738" }, vector: [0.5438, 0.1299, 0.3760] }) +Item 47: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7506" }, vector: [0.7083, 0.1976, 0.1506] }) +Item 48: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1406" }, vector: [0.7304, 0.5688, 0.6662] }) +Item 49: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1160" }, vector: [0.3805, 0.8072, 0.6701] }) +Item 50: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9121" }, vector: [0.0684, 0.8029, 0.4273] }) +Item 51: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8113" }, vector: [0.3427, 0.1293, 0.7240] }) +Item 52: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2950" }, vector: [0.5500, 0.9148, 0.7332] }) +Item 53: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8488" }, vector: [0.4014, 0.2562, 0.7026] }) +Item 54: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3913" }, vector: [0.9506, 0.5606, 0.8472] }) +Item 55: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8270" }, vector: [0.1645, 0.1968, 0.7862] }) +Item 56: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3288" }, vector: [0.4429, 0.7944, 0.9688] }) +Item 57: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8996" }, vector: [0.6386, 0.5482, 0.3175] }) +Item 58: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9797" }, vector: [0.3389, 0.4818, 0.7828] }) +Item 59: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7839" }, vector: [0.5580, 0.3213, 0.4471] }) +Item 60: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7833" }, vector: [0.7237, 0.2860, 0.0901] }) +Item 61: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0168" }, vector: [0.9176, 0.4249, 0.1069] }) +Item 62: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8952" }, vector: [0.4310, 0.0837, 0.7802] }) +Item 63: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0165" }, vector: [0.7313, 0.3394, 0.6192] }) +Item 64: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9699" }, vector: [0.8863, 0.1804, 0.3504] }) +Item 65: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0281" }, vector: [0.5298, 0.8744, 0.1086] }) +Item 66: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2347" }, vector: [0.7707, 0.7848, 0.5609] }) +Item 67: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8433" }, vector: [0.5919, 0.0467, 0.5988] }) +Item 68: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9905" }, vector: [0.0585, 0.3819, 0.9120] }) +Item 69: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.1911" }, vector: [0.1383, 0.1076, 0.0762] }) +Item 70: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.4642" }, vector: [0.8155, 0.8139, 0.9035] }) +Item 71: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.5580" }, vector: [0.3705, 0.3807, 0.1708] }) +Item 72: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7419" }, vector: [0.2916, 0.6647, 0.1535] }) +Item 73: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9156" }, vector: [0.4826, 0.0217, 0.7778] }) +Item 74: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9966" }, vector: [0.2028, 0.9424, 0.2528] }) +Item 75: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7771" }, vector: [0.6375, 0.1274, 0.4257] }) +Item 76: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8002" }, vector: [0.1006, 0.4131, 0.6779] }) +Item 77: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.2842" }, vector: [0.2800, 0.0278, 0.0397] }) +Item 78: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7925" }, vector: [0.4195, 0.6031, 0.2970] }) +Item 79: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1725" }, vector: [0.3166, 0.5944, 0.9598] }) +Item 80: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0432" }, vector: [0.9485, 0.0272, 0.4336] }) +Item 81: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9749" }, vector: [0.7733, 0.5495, 0.2244] }) +Item 82: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8740" }, vector: [0.1339, 0.2209, 0.8350] }) +Item 83: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.5051" }, vector: [0.1072, 0.4570, 0.1867] }) +Item 84: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0568" }, vector: [0.2566, 0.9481, 0.3899] }) +Item 85: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2351" }, vector: [0.6583, 0.8015, 0.6706] }) +Item 86: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0194" }, vector: [0.9689, 0.2817, 0.1451] }) +Item 87: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3859" }, vector: [0.9524, 0.4419, 0.9046] }) +Item 88: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.1995" }, vector: [0.1504, 0.0124, 0.1305] }) +Item 89: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2740" }, vector: [0.9664, 0.0525, 0.8284] }) +Item 90: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0572" }, vector: [0.9029, 0.4726, 0.2814] }) +Item 91: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1088" }, vector: [0.4464, 0.7439, 0.6904] }) +Item 92: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9216" }, vector: [0.2904, 0.8287, 0.2799] }) +Item 93: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3908" }, vector: [0.9963, 0.2933, 0.9251] }) +Item 94: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3501" }, vector: [0.9755, 0.4346, 0.8260] }) +Item 95: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7770" }, vector: [0.4079, 0.0195, 0.6610] }) +Item 96: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0922" }, vector: [0.5369, 0.8875, 0.3421] }) +Item 97: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7225" }, vector: [0.4484, 0.5659, 0.0259] }) +Item 98: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1565" }, vector: [0.7837, 0.4348, 0.7310] }) +Item 99: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.5328" }, vector: [0.9591, 0.9487, 0.7276] }) +Item 100: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7411" }, vector: [0.5390, 0.4001, 0.3141] }) +Item 101: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9705" }, vector: [0.8369, 0.4671, 0.1519] }) +Item 102: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9412" }, vector: [0.5237, 0.1241, 0.7721] }) +Item 103: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.5568" }, vector: [0.0097, 0.3834, 0.4036] }) +Item 104: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.1946" }, vector: [0.0274, 0.1508, 0.1198] }) +Item 105: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9778" }, vector: [0.0151, 0.9768, 0.0396] }) +Item 106: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7807" }, vector: [0.1998, 0.5217, 0.5453] }) +Item 107: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8917" }, vector: [0.6266, 0.2753, 0.5716] }) +Item 108: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7514" }, vector: [0.7083, 0.0762, 0.2390] }) +Item 109: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.5511" }, vector: [0.0972, 0.0819, 0.5362] }) +Item 110: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9070" }, vector: [0.8215, 0.2263, 0.3109] }) +Item 111: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8462" }, vector: [0.2738, 0.6133, 0.5147] }) +Item 112: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.4499" }, vector: [0.9334, 0.9877, 0.5054] }) +Item 113: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0514" }, vector: [0.8811, 0.4353, 0.3735] }) +Item 114: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2423" }, vector: [0.7596, 0.8341, 0.5202] }) +Item 115: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9094" }, vector: [0.8083, 0.0235, 0.4160] }) +Item 116: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7452" }, vector: [0.1656, 0.6664, 0.2896] }) +Item 117: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0026" }, vector: [0.5461, 0.7987, 0.2628] }) +Item 118: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0341" }, vector: [0.7858, 0.5026, 0.4464] }) +Item 119: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9175" }, vector: [0.4663, 0.5407, 0.5762] }) +Item 120: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9376" }, vector: [0.7453, 0.1027, 0.5595] }) +Item 121: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3753" }, vector: [0.5039, 0.8272, 0.9763] }) +Item 122: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0754" }, vector: [0.9918, 0.1477, 0.3887] }) +Item 123: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3925" }, vector: [0.8795, 0.8468, 0.6697] }) +Item 124: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1098" }, vector: [0.7647, 0.7957, 0.1173] }) +Item 125: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1476" }, vector: [0.9591, 0.4926, 0.3932] }) +Item 126: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9134" }, vector: [0.5712, 0.5981, 0.3877] }) +Item 127: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9111" }, vector: [0.3695, 0.2631, 0.7901] }) +Item 128: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1932" }, vector: [0.6963, 0.9067, 0.3417] }) +Item 129: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9262" }, vector: [0.5209, 0.1390, 0.7531] }) +Item 130: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3670" }, vector: [0.3249, 0.8754, 0.9984] }) +Item 131: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7638" }, vector: [0.7362, 0.0281, 0.2016] }) +Item 132: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9733" }, vector: [0.9443, 0.1989, 0.1268] }) +Item 133: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1471" }, vector: [0.7461, 0.2756, 0.8266] }) +Item 134: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8314" }, vector: [0.0999, 0.5222, 0.6392] }) +Item 135: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.5262" }, vector: [0.9377, 0.9354, 0.7583] }) +Item 136: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2001" }, vector: [0.1164, 0.8645, 0.8242] }) +Item 137: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.4666" }, vector: [0.1620, 0.2974, 0.3209] }) +Item 138: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1939" }, vector: [0.9473, 0.4661, 0.5575] }) +Item 139: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0903" }, vector: [0.2633, 0.9335, 0.4981] }) +Item 140: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.5685" }, vector: [0.2509, 0.4837, 0.1620] }) +Item 141: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.1324" }, vector: [0.1082, 0.0741, 0.0183] }) +Item 142: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9244" }, vector: [0.5846, 0.5706, 0.4327] }) +Item 143: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3347" }, vector: [0.9265, 0.9559, 0.0970] }) +Item 144: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7351" }, vector: [0.7162, 0.1286, 0.1047] }) +Item 145: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0301" }, vector: [0.7652, 0.5422, 0.4261] }) +Item 146: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0697" }, vector: [0.2670, 0.8095, 0.6462] }) +Item 147: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8406" }, vector: [0.1504, 0.0946, 0.8216] }) +Item 148: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0285" }, vector: [0.1483, 0.2682, 0.9818] }) +Item 149: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1411" }, vector: [0.2397, 0.6252, 0.9240] }) diff --git a/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points_with_little_memory.snap b/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points_with_little_memory.snap new file mode 100644 index 0000000..32e6847 --- /dev/null +++ b/src/tests/snapshots/arroy__tests__writer__write_and_update_lot_of_random_points_with_little_memory.snap @@ -0,0 +1,296 @@ +--- +source: src/tests/writer.rs +expression: handle +--- +================== +Dumping index 0 +Root: Metadata { dimensions: 3, items: RoaringBitmap<100 values between 0 and 99>, roots: [0, 1], distance: "cosine" } +Version: Version { major: 0, minor: 7, patch: 0 } +Tree 0: SplitPlaneNormal(SplitPlaneNormal { left: 94, right: 95, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.7419, -0.0092, 0.6705] } }) +Tree 1: SplitPlaneNormal(SplitPlaneNormal { left: 2, right: 3, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.5938, 0.3404, -0.7290] } }) +Tree 2: SplitPlaneNormal(SplitPlaneNormal { left: 64, right: 65, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5969, 0.7955, -0.1042] } }) +Tree 3: SplitPlaneNormal(SplitPlaneNormal { left: 4, right: 5, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6720, -0.7180, 0.1817] } }) +Tree 4: SplitPlaneNormal(SplitPlaneNormal { left: 42, right: 43, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8971, 0.4184, 0.1423] } }) +Tree 5: SplitPlaneNormal(SplitPlaneNormal { left: 6, right: 7, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.2091, -0.4533, 0.8665] } }) +Tree 6: SplitPlaneNormal(SplitPlaneNormal { left: 26, right: 27, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3881, 0.4833, 0.7847] } }) +Tree 7: SplitPlaneNormal(SplitPlaneNormal { left: 8, right: 9, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.0141, 0.8224, -0.5688] } }) +Tree 8: SplitPlaneNormal(SplitPlaneNormal { left: 16, right: 17, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6128, 0.7615, 0.2113] } }) +Tree 9: SplitPlaneNormal(SplitPlaneNormal { left: 10, right: 11, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7223, -0.6315, -0.2819] } }) +Tree 10: SplitPlaneNormal(SplitPlaneNormal { left: 14, right: 15, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6219, -0.0774, 0.7793] } }) +Tree 11: SplitPlaneNormal(SplitPlaneNormal { left: 12, right: 13, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4038, 0.3552, -0.8431] } }) +Tree 12: Descendants(Descendants { descendants: [52, 59] }) +Tree 13: Descendants(Descendants { descendants: [10, 58] }) +Tree 14: Descendants(Descendants { descendants: [21, 39] }) +Tree 15: Descendants(Descendants { descendants: [9, 60] }) +Tree 16: SplitPlaneNormal(SplitPlaneNormal { left: 18, right: 19, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4400, -0.6017, -0.6666] } }) +Tree 17: Descendants(Descendants { descendants: [29, 48, 68] }) +Tree 18: SplitPlaneNormal(SplitPlaneNormal { left: 20, right: 21, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6356, -0.3787, -0.6728] } }) +Tree 19: Descendants(Descendants { descendants: [4, 8, 11] }) +Tree 20: SplitPlaneNormal(SplitPlaneNormal { left: 22, right: 23, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.0340, -0.9313, 0.3626] } }) +Tree 21: Descendants(Descendants { descendants: [40, 75] }) +Tree 22: Descendants(Descendants { descendants: [63, 87] }) +Tree 23: SplitPlaneNormal(SplitPlaneNormal { left: 24, right: 25, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.5292, 0.3868, -0.7553] } }) +Tree 24: Descendants(Descendants { descendants: [0, 93] }) +Tree 25: Descendants(Descendants { descendants: [78, 82] }) +Tree 26: SplitPlaneNormal(SplitPlaneNormal { left: 40, right: 41, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.1973, 0.9757, 0.0950] } }) +Tree 27: SplitPlaneNormal(SplitPlaneNormal { left: 28, right: 29, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6078, -0.7489, -0.2641] } }) +Tree 28: SplitPlaneNormal(SplitPlaneNormal { left: 34, right: 35, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6381, -0.4144, -0.6490] } }) +Tree 29: SplitPlaneNormal(SplitPlaneNormal { left: 30, right: 31, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3553, -0.9153, 0.1896] } }) +Tree 30: SplitPlaneNormal(SplitPlaneNormal { left: 32, right: 33, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2376, 0.2217, -0.9457] } }) +Tree 31: Descendants(Descendants { descendants: [15, 80] }) +Tree 32: Descendants(Descendants { descendants: [98] }) +Tree 33: Descendants(Descendants { descendants: [1, 22, 84] }) +Tree 34: SplitPlaneNormal(SplitPlaneNormal { left: 36, right: 37, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7289, -0.4821, -0.4861] } }) +Tree 35: Descendants(Descendants { descendants: [19, 81] }) +Tree 36: Descendants(Descendants { descendants: [6, 33, 99] }) +Tree 37: SplitPlaneNormal(SplitPlaneNormal { left: 38, right: 39, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.4520, 0.7619, -0.4638] } }) +Tree 38: Descendants(Descendants { descendants: [57, 69] }) +Tree 39: Descendants(Descendants { descendants: [45, 71] }) +Tree 40: Descendants(Descendants { descendants: [5, 27, 77] }) +Tree 41: Descendants(Descendants { descendants: [17, 47, 61] }) +Tree 42: SplitPlaneNormal(SplitPlaneNormal { left: 52, right: 53, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.1610, 0.3819, -0.9101] } }) +Tree 43: SplitPlaneNormal(SplitPlaneNormal { left: 44, right: 45, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.2809, -0.1702, 0.9445] } }) +Tree 44: Descendants(Descendants { descendants: [34] }) +Tree 45: SplitPlaneNormal(SplitPlaneNormal { left: 46, right: 47, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1491, 0.5140, -0.8448] } }) +Tree 46: SplitPlaneNormal(SplitPlaneNormal { left: 50, right: 51, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1298, -0.6816, 0.7201] } }) +Tree 47: SplitPlaneNormal(SplitPlaneNormal { left: 48, right: 49, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.8454, -0.4542, 0.2812] } }) +Tree 48: Descendants(Descendants { descendants: [41, 76, 83] }) +Tree 49: Descendants(Descendants { descendants: [13, 23, 92] }) +Tree 50: Descendants(Descendants { descendants: [36, 49] }) +Tree 51: Descendants(Descendants { descendants: [2, 91] }) +Tree 52: SplitPlaneNormal(SplitPlaneNormal { left: 56, right: 57, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6084, -0.1180, -0.7848] } }) +Tree 53: SplitPlaneNormal(SplitPlaneNormal { left: 54, right: 55, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.7969, 0.5480, 0.2541] } }) +Tree 54: Descendants(Descendants { descendants: [12, 97] }) +Tree 55: Descendants(Descendants { descendants: [14, 65, 72] }) +Tree 56: SplitPlaneNormal(SplitPlaneNormal { left: 58, right: 59, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3148, -0.3591, 0.8786] } }) +Tree 57: Descendants(Descendants { descendants: [24, 31, 42] }) +Tree 58: SplitPlaneNormal(SplitPlaneNormal { left: 60, right: 61, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.4706, 0.6113, -0.6363] } }) +Tree 59: Descendants(Descendants { descendants: [85] }) +Tree 60: SplitPlaneNormal(SplitPlaneNormal { left: 62, right: 63, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3742, -0.6750, 0.6359] } }) +Tree 61: Descendants(Descendants { descendants: [38] }) +Tree 62: Descendants(Descendants { descendants: [16, 18] }) +Tree 63: Descendants(Descendants { descendants: [90, 96] }) +Tree 64: SplitPlaneNormal(SplitPlaneNormal { left: 80, right: 81, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7926, -0.2856, -0.5388] } }) +Tree 65: SplitPlaneNormal(SplitPlaneNormal { left: 66, right: 67, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.0680, 0.7454, -0.6632] } }) +Tree 66: SplitPlaneNormal(SplitPlaneNormal { left: 74, right: 75, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.7091, 0.5040, -0.4931] } }) +Tree 67: SplitPlaneNormal(SplitPlaneNormal { left: 68, right: 69, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.5085, 0.4515, -0.7332] } }) +Tree 68: Descendants(Descendants { descendants: [20, 50] }) +Tree 69: SplitPlaneNormal(SplitPlaneNormal { left: 70, right: 71, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6425, 0.4399, -0.6274] } }) +Tree 70: SplitPlaneNormal(SplitPlaneNormal { left: 72, right: 73, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.8015, -0.4493, 0.3947] } }) +Tree 71: Descendants(Descendants { descendants: [54] }) +Tree 72: Descendants(Descendants { descendants: [25, 26, 66] }) +Tree 73: Descendants(Descendants { descendants: [32] }) +Tree 74: SplitPlaneNormal(SplitPlaneNormal { left: 78, right: 79, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6325, -0.7151, 0.2977] } }) +Tree 75: SplitPlaneNormal(SplitPlaneNormal { left: 76, right: 77, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8716, 0.0210, 0.4898] } }) +Tree 76: Descendants(Descendants { descendants: [70, 94] }) +Tree 77: Descendants(Descendants { descendants: [74, 79, 86] }) +Tree 78: Descendants(Descendants { descendants: [3, 30] }) +Tree 79: Descendants(Descendants { descendants: [28, 43] }) +Tree 80: SplitPlaneNormal(SplitPlaneNormal { left: 88, right: 89, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4346, 0.7756, -0.4578] } }) +Tree 81: SplitPlaneNormal(SplitPlaneNormal { left: 82, right: 83, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3623, 0.9297, 0.0661] } }) +Tree 82: SplitPlaneNormal(SplitPlaneNormal { left: 84, right: 85, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.0722, 0.9920, -0.1031] } }) +Tree 83: Descendants(Descendants { descendants: [44] }) +Tree 84: SplitPlaneNormal(SplitPlaneNormal { left: 86, right: 87, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6043, 0.4030, -0.6874] } }) +Tree 85: Descendants(Descendants { descendants: [56] }) +Tree 86: Descendants(Descendants { descendants: [35, 67] }) +Tree 87: Descendants(Descendants { descendants: [88, 89] }) +Tree 88: SplitPlaneNormal(SplitPlaneNormal { left: 90, right: 91, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.9628, -0.0719, 0.2605] } }) +Tree 89: Descendants(Descendants { descendants: [7, 53, 64] }) +Tree 90: SplitPlaneNormal(SplitPlaneNormal { left: 92, right: 93, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8021, 0.4808, 0.3542] } }) +Tree 91: Descendants(Descendants { descendants: [55, 62] }) +Tree 92: Descendants(Descendants { descendants: [73, 95] }) +Tree 93: Descendants(Descendants { descendants: [37, 46, 51] }) +Tree 94: SplitPlaneNormal(SplitPlaneNormal { left: 128, right: 129, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4785, -0.8779, -0.0195] } }) +Tree 95: SplitPlaneNormal(SplitPlaneNormal { left: 96, right: 97, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.9268, -0.3400, -0.1595] } }) +Tree 96: SplitPlaneNormal(SplitPlaneNormal { left: 114, right: 115, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.0640, 0.8356, -0.5456] } }) +Tree 97: SplitPlaneNormal(SplitPlaneNormal { left: 98, right: 99, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1260, 0.8927, -0.4327] } }) +Tree 98: SplitPlaneNormal(SplitPlaneNormal { left: 108, right: 109, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3363, -0.8669, 0.3680] } }) +Tree 99: SplitPlaneNormal(SplitPlaneNormal { left: 100, right: 101, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.8726, -0.1613, -0.4610] } }) +Tree 100: SplitPlaneNormal(SplitPlaneNormal { left: 104, right: 105, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.0318, -0.7392, 0.6728] } }) +Tree 101: SplitPlaneNormal(SplitPlaneNormal { left: 102, right: 103, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3143, -0.7022, 0.6389] } }) +Tree 102: Descendants(Descendants { descendants: [48, 70, 94] }) +Tree 103: Descendants(Descendants { descendants: [44, 64] }) +Tree 104: Descendants(Descendants { descendants: [2, 36, 91] }) +Tree 105: SplitPlaneNormal(SplitPlaneNormal { left: 106, right: 107, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6759, 0.4713, -0.5666] } }) +Tree 106: Descendants(Descendants { descendants: [28] }) +Tree 107: Descendants(Descendants { descendants: [7, 74, 86] }) +Tree 108: Descendants(Descendants { descendants: [53] }) +Tree 109: SplitPlaneNormal(SplitPlaneNormal { left: 110, right: 111, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8863, -0.1858, 0.4241] } }) +Tree 110: SplitPlaneNormal(SplitPlaneNormal { left: 112, right: 113, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6023, 0.7592, 0.2465] } }) +Tree 111: Descendants(Descendants { descendants: [37] }) +Tree 112: Descendants(Descendants { descendants: [73, 95] }) +Tree 113: Descendants(Descendants { descendants: [46, 51] }) +Tree 114: SplitPlaneNormal(SplitPlaneNormal { left: 126, right: 127, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1874, 0.9064, -0.3786] } }) +Tree 115: SplitPlaneNormal(SplitPlaneNormal { left: 116, right: 117, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.4503, 0.5907, -0.6696] } }) +Tree 116: SplitPlaneNormal(SplitPlaneNormal { left: 122, right: 123, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.8347, 0.2874, -0.4699] } }) +Tree 117: SplitPlaneNormal(SplitPlaneNormal { left: 118, right: 119, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5426, -0.3202, 0.7766] } }) +Tree 118: Descendants(Descendants { descendants: [76, 83] }) +Tree 119: SplitPlaneNormal(SplitPlaneNormal { left: 120, right: 121, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5526, 0.4617, -0.6938] } }) +Tree 120: Descendants(Descendants { descendants: [25, 26, 66] }) +Tree 121: Descendants(Descendants { descendants: [54] }) +Tree 122: SplitPlaneNormal(SplitPlaneNormal { left: 124, right: 125, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6193, 0.5548, -0.5555] } }) +Tree 123: Descendants(Descendants { descendants: [32, 49] }) +Tree 124: Descendants(Descendants { descendants: [3, 30, 50] }) +Tree 125: Descendants(Descendants { descendants: [20] }) +Tree 126: Descendants(Descendants { descendants: [43, 55, 62] }) +Tree 127: Descendants(Descendants { descendants: [79] }) +Tree 128: SplitPlaneNormal(SplitPlaneNormal { left: 152, right: 153, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6325, 0.7077, -0.3149] } }) +Tree 129: SplitPlaneNormal(SplitPlaneNormal { left: 130, right: 131, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3229, 0.5291, -0.7847] } }) +Tree 130: SplitPlaneNormal(SplitPlaneNormal { left: 140, right: 141, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.5718, -0.3132, 0.7583] } }) +Tree 131: SplitPlaneNormal(SplitPlaneNormal { left: 132, right: 133, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.0720, -0.5319, 0.8437] } }) +Tree 132: SplitPlaneNormal(SplitPlaneNormal { left: 136, right: 137, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.3891, -0.6811, -0.6202] } }) +Tree 133: SplitPlaneNormal(SplitPlaneNormal { left: 134, right: 135, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.0610, -0.9292, 0.3644] } }) +Tree 134: Descendants(Descendants { descendants: [15, 40, 80] }) +Tree 135: Descendants(Descendants { descendants: [4, 8] }) +Tree 136: Descendants(Descendants { descendants: [22, 84] }) +Tree 137: SplitPlaneNormal(SplitPlaneNormal { left: 138, right: 139, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.2183, 0.8233, 0.5240] } }) +Tree 138: Descendants(Descendants { descendants: [5, 27, 77] }) +Tree 139: Descendants(Descendants { descendants: [17, 47, 61] }) +Tree 140: SplitPlaneNormal(SplitPlaneNormal { left: 148, right: 149, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4907, -0.7578, -0.4301] } }) +Tree 141: SplitPlaneNormal(SplitPlaneNormal { left: 142, right: 143, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.1645, -0.9636, 0.2109] } }) +Tree 142: Descendants(Descendants { descendants: [87] }) +Tree 143: SplitPlaneNormal(SplitPlaneNormal { left: 144, right: 145, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.0415, 0.9886, -0.1449] } }) +Tree 144: SplitPlaneNormal(SplitPlaneNormal { left: 146, right: 147, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6677, -0.1664, 0.7256] } }) +Tree 145: Descendants(Descendants { descendants: [56, 93] }) +Tree 146: Descendants(Descendants { descendants: [88, 89] }) +Tree 147: Descendants(Descendants { descendants: [35, 67] }) +Tree 148: SplitPlaneNormal(SplitPlaneNormal { left: 150, right: 151, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.3166, 0.9469, -0.0553] } }) +Tree 149: Descendants(Descendants { descendants: [11, 75] }) +Tree 150: Descendants(Descendants { descendants: [0, 78, 82] }) +Tree 151: Descendants(Descendants { descendants: [63] }) +Tree 152: SplitPlaneNormal(SplitPlaneNormal { left: 166, right: 167, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.1407, 0.7156, -0.6842] } }) +Tree 153: SplitPlaneNormal(SplitPlaneNormal { left: 154, right: 155, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.5494, -0.1561, -0.8208] } }) +Tree 154: SplitPlaneNormal(SplitPlaneNormal { left: 160, right: 161, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.8677, -0.4957, -0.0375] } }) +Tree 155: SplitPlaneNormal(SplitPlaneNormal { left: 156, right: 157, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.8505, 0.5224, -0.0614] } }) +Tree 156: SplitPlaneNormal(SplitPlaneNormal { left: 158, right: 159, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.7746, 0.6224, -0.1124] } }) +Tree 157: Descendants(Descendants { descendants: [14, 34] }) +Tree 158: Descendants(Descendants { descendants: [12, 42] }) +Tree 159: Descendants(Descendants { descendants: [65, 72, 97] }) +Tree 160: SplitPlaneNormal(SplitPlaneNormal { left: 164, right: 165, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.7947, 0.5223, -0.3094] } }) +Tree 161: SplitPlaneNormal(SplitPlaneNormal { left: 162, right: 163, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.5999, -0.1255, -0.7902] } }) +Tree 162: Descendants(Descendants { descendants: [16, 18, 38] }) +Tree 163: Descendants(Descendants { descendants: [24] }) +Tree 164: Descendants(Descendants { descendants: [13, 23] }) +Tree 165: Descendants(Descendants { descendants: [41, 92] }) +Tree 166: SplitPlaneNormal(SplitPlaneNormal { left: 178, right: 179, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6048, -0.0853, 0.7918] } }) +Tree 167: SplitPlaneNormal(SplitPlaneNormal { left: 168, right: 169, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6431, -0.6135, -0.4582] } }) +Tree 168: SplitPlaneNormal(SplitPlaneNormal { left: 170, right: 171, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6919, -0.1450, -0.7073] } }) +Tree 169: Descendants(Descendants { descendants: [1, 19, 81] }) +Tree 170: Descendants(Descendants { descendants: [85, 90] }) +Tree 171: SplitPlaneNormal(SplitPlaneNormal { left: 172, right: 173, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.4012, 0.1846, -0.8972] } }) +Tree 172: Descendants(Descendants { descendants: [33, 99] }) +Tree 173: SplitPlaneNormal(SplitPlaneNormal { left: 174, right: 175, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6930, -0.7206, -0.0238] } }) +Tree 174: SplitPlaneNormal(SplitPlaneNormal { left: 176, right: 177, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.6883, -0.3049, -0.6582] } }) +Tree 175: Descendants(Descendants { descendants: [57, 69] }) +Tree 176: Descendants(Descendants { descendants: [31, 96] }) +Tree 177: Descendants(Descendants { descendants: [6, 45, 71] }) +Tree 178: SplitPlaneNormal(SplitPlaneNormal { left: 184, right: 185, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.6981, 0.6082, 0.3780] } }) +Tree 179: SplitPlaneNormal(SplitPlaneNormal { left: 180, right: 181, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.2183, 0.8496, -0.4801] } }) +Tree 180: SplitPlaneNormal(SplitPlaneNormal { left: 182, right: 183, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [0.2662, 0.6364, -0.7240] } }) +Tree 181: Descendants(Descendants { descendants: [60] }) +Tree 182: Descendants(Descendants { descendants: [29, 68] }) +Tree 183: Descendants(Descendants { descendants: [9, 52] }) +Tree 184: SplitPlaneNormal(SplitPlaneNormal { left: 186, right: 187, normal: Leaf { header: NodeHeaderCosine { norm: "0.0000" }, vector: [-0.4736, -0.0890, 0.8762] } }) +Tree 185: Descendants(Descendants { descendants: [21, 39] }) +Tree 186: Descendants(Descendants { descendants: [98] }) +Tree 187: Descendants(Descendants { descendants: [10, 58, 59] }) +Item 0: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0872" }, vector: [0.8013, 0.2371, 0.6955] }) +Item 1: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0443" }, vector: [0.8606, 0.5280, 0.2667] }) +Item 2: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.4908" }, vector: [0.6057, 0.9830, 0.9430] }) +Item 3: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.5378" }, vector: [0.0479, 0.2927, 0.4487] }) +Item 4: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9436" }, vector: [0.8798, 0.0246, 0.3401] }) +Item 5: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7470" }, vector: [0.7418, 0.0595, 0.0652] }) +Item 6: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1644" }, vector: [0.7750, 0.7425, 0.4517] }) +Item 7: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.4776" }, vector: [0.2155, 0.1841, 0.3845] }) +Item 8: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1195" }, vector: [0.9954, 0.1512, 0.4894] }) +Item 9: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.5567" }, vector: [0.9152, 0.7847, 0.9849] }) +Item 10: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.5616" }, vector: [0.4199, 0.2620, 0.2655] }) +Item 11: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9246" }, vector: [0.8414, 0.0192, 0.3828] }) +Item 12: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.3734" }, vector: [0.2561, 0.2692, 0.0368] }) +Item 13: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1116" }, vector: [0.4624, 0.8739, 0.5080] }) +Item 14: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0011" }, vector: [0.4557, 0.8887, 0.0685] }) +Item 15: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.6977" }, vector: [0.6341, 0.1904, 0.2201] }) +Item 16: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1907" }, vector: [0.6947, 0.8503, 0.4607] }) +Item 17: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.6904" }, vector: [0.6554, 0.2088, 0.0586] }) +Item 18: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2539" }, vector: [0.6857, 0.9343, 0.4788] }) +Item 19: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2199" }, vector: [0.9246, 0.7944, 0.0473] }) +Item 20: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2728" }, vector: [0.1040, 0.9647, 0.8238] }) +Item 21: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8493" }, vector: [0.5344, 0.4903, 0.4420] }) +Item 22: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9142" }, vector: [0.7937, 0.4028, 0.2083] }) +Item 23: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7987" }, vector: [0.3315, 0.6684, 0.2849] }) +Item 24: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2609" }, vector: [0.8002, 0.9037, 0.3644] }) +Item 25: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9546" }, vector: [0.1173, 0.7807, 0.5366] }) +Item 26: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1379" }, vector: [0.1554, 0.9343, 0.6308] }) +Item 27: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.3820" }, vector: [0.3727, 0.0552, 0.0634] }) +Item 28: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1230" }, vector: [0.3584, 0.4273, 0.9748] }) +Item 29: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.4602" }, vector: [0.8893, 0.6025, 0.9890] }) +Item 30: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2471" }, vector: [0.0001, 0.7870, 0.9674] }) +Item 31: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7464" }, vector: [0.4568, 0.5250, 0.2701] }) +Item 32: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1377" }, vector: [0.2417, 0.8742, 0.6869] }) +Item 33: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3377" }, vector: [0.8759, 0.8323, 0.5742] }) +Item 34: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7853" }, vector: [0.3201, 0.7171, 0.0057] }) +Item 35: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8325" }, vector: [0.6038, 0.0168, 0.5729] }) +Item 36: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0547" }, vector: [0.4393, 0.7574, 0.5881] }) +Item 37: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9081" }, vector: [0.2978, 0.0910, 0.8530] }) +Item 38: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0339" }, vector: [0.5171, 0.8481, 0.2869] }) +Item 39: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7896" }, vector: [0.5211, 0.4583, 0.3767] }) +Item 40: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0489" }, vector: [0.8616, 0.3239, 0.5030] }) +Item 41: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9873" }, vector: [0.3022, 0.8817, 0.3255] }) +Item 42: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3946" }, vector: [0.9170, 0.9928, 0.3439] }) +Item 43: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.6672" }, vector: [0.0860, 0.2202, 0.6240] }) +Item 44: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0014" }, vector: [0.6195, 0.3361, 0.7113] }) +Item 45: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2019" }, vector: [0.8040, 0.7845, 0.4275] }) +Item 46: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8810" }, vector: [0.3626, 0.1384, 0.7909] }) +Item 47: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7506" }, vector: [0.7083, 0.1976, 0.1506] }) +Item 48: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1895" }, vector: [0.6972, 0.5359, 0.8010] }) +Item 49: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1160" }, vector: [0.3805, 0.8072, 0.6701] }) +Item 50: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1789" }, vector: [0.0850, 0.7778, 0.8818] }) +Item 51: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8113" }, vector: [0.3427, 0.1293, 0.7240] }) +Item 52: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.6850" }, vector: [0.4773, 0.2871, 0.3988] }) +Item 53: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8488" }, vector: [0.4014, 0.2562, 0.7026] }) +Item 54: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.4090" }, vector: [0.0131, 0.3608, 0.1922] }) +Item 55: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8270" }, vector: [0.1645, 0.1968, 0.7862] }) +Item 56: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2929" }, vector: [0.9030, 0.2735, 0.8840] }) +Item 57: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8996" }, vector: [0.6386, 0.5482, 0.3175] }) +Item 58: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1399" }, vector: [0.8519, 0.5081, 0.5617] }) +Item 59: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7839" }, vector: [0.5580, 0.3213, 0.4471] }) +Item 60: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.5511" }, vector: [0.8761, 0.9344, 0.8748] }) +Item 61: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0168" }, vector: [0.9176, 0.4249, 0.1069] }) +Item 62: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0041" }, vector: [0.0392, 0.1024, 0.9981] }) +Item 63: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0165" }, vector: [0.7313, 0.3394, 0.6192] }) +Item 64: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9513" }, vector: [0.4707, 0.3849, 0.7316] }) +Item 65: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0281" }, vector: [0.5298, 0.8744, 0.1086] }) +Item 66: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8002" }, vector: [0.0631, 0.6646, 0.4413] }) +Item 67: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8433" }, vector: [0.5919, 0.0467, 0.5988] }) +Item 68: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2920" }, vector: [0.8101, 0.4828, 0.8831] }) +Item 69: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.1911" }, vector: [0.1383, 0.1076, 0.0762] }) +Item 70: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1321" }, vector: [0.5699, 0.5919, 0.7788] }) +Item 71: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.5580" }, vector: [0.3705, 0.3807, 0.1708] }) +Item 72: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.6752" }, vector: [0.3678, 0.5629, 0.0612] }) +Item 73: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9156" }, vector: [0.4826, 0.0217, 0.7778] }) +Item 74: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.6857" }, vector: [0.2831, 0.3242, 0.5338] }) +Item 75: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7771" }, vector: [0.6375, 0.1274, 0.4257] }) +Item 76: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9184" }, vector: [0.2305, 0.7650, 0.4528] }) +Item 77: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.2842" }, vector: [0.2800, 0.0278, 0.0397] }) +Item 78: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8796" }, vector: [0.6639, 0.2003, 0.5412] }) +Item 79: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1725" }, vector: [0.3166, 0.5944, 0.9598] }) +Item 80: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1152" }, vector: [0.9520, 0.3982, 0.4226] }) +Item 81: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.9749" }, vector: [0.7733, 0.5495, 0.2244] }) +Item 82: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.0292" }, vector: [0.7816, 0.2531, 0.6199] }) +Item 83: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.5051" }, vector: [0.1072, 0.4570, 0.1867] }) +Item 84: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.6358" }, vector: [0.5403, 0.2813, 0.1820] }) +Item 85: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2351" }, vector: [0.6583, 0.8015, 0.6706] }) +Item 86: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8018" }, vector: [0.3091, 0.4282, 0.6033] }) +Item 87: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3859" }, vector: [0.9524, 0.4419, 0.9046] }) +Item 88: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.3135" }, vector: [0.2348, 0.0132, 0.2073] }) +Item 89: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.2740" }, vector: [0.9664, 0.0525, 0.8284] }) +Item 90: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.4259" }, vector: [0.8134, 0.9647, 0.6640] }) +Item 91: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1088" }, vector: [0.4464, 0.7439, 0.6904] }) +Item 92: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.8943" }, vector: [0.3159, 0.7607, 0.3483] }) +Item 93: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3908" }, vector: [0.9963, 0.2933, 0.9251] }) +Item 94: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.2017" }, vector: [0.1057, 0.1036, 0.1371] }) +Item 95: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7770" }, vector: [0.4079, 0.0195, 0.6610] }) +Item 96: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.3821" }, vector: [0.8298, 0.9571, 0.5529] }) +Item 97: Leaf(Leaf { header: NodeHeaderCosine { norm: "0.7225" }, vector: [0.4484, 0.5659, 0.0259] }) +Item 98: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.1580" }, vector: [0.9343, 0.5204, 0.4442] }) +Item 99: Leaf(Leaf { header: NodeHeaderCosine { norm: "1.5328" }, vector: [0.9591, 0.9487, 0.7276] }) diff --git a/src/tests/writer.rs b/src/tests/writer.rs index f504535..d40239a 100644 --- a/src/tests/writer.rs +++ b/src/tests/writer.rs @@ -1371,3 +1371,31 @@ fn cancel_indexing_process() { .unwrap_err(); assert_snapshot!(err, @"The corresponding build process has been cancelled"); } + +#[test] +fn write_and_update_lot_of_random_points_with_little_memory() { + let handle = create_database::(); + let mut wtxn = handle.env.write_txn().unwrap(); + let writer = Writer::new(handle.database, 0, 3); + let mut rng = rng(); + for id in 0..100 { + let vector: [f32; 3] = std::array::from_fn(|_| rng.gen()); + writer.add_item(&mut wtxn, id, &vector).unwrap(); + } + + // With 0 bytes of memory, the builder will default to the size of a descendant + 1 + writer.builder(&mut rng).available_memory(0).n_trees(2).build(&mut wtxn).unwrap(); + wtxn.commit().unwrap(); + insta::assert_snapshot!(handle); + + let mut wtxn = handle.env.write_txn().unwrap(); + let writer = Writer::new(handle.database, 0, 3); + for id in (0..100).step_by(2).chain(100..150) { + let vector: [f32; 3] = std::array::from_fn(|_| rng.gen()); + writer.add_item(&mut wtxn, id, &vector).unwrap(); + } + writer.builder(&mut rng).available_memory(0).n_trees(3).build(&mut wtxn).unwrap(); + wtxn.commit().unwrap(); + + insta::assert_snapshot!(handle); +} diff --git a/src/writer.rs b/src/writer.rs index 03bcfa2..0b38996 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1481,8 +1481,8 @@ pub(crate) fn fit_in_memory( dbg!(&nb_items); // We must insert at least dimensions items to create a split - let nb_items = if nb_items < dimensions { - dimensions + let nb_items = if nb_items <= dimensions { + dimensions + 1 } else { nb_items }; From ccdafc20e7f6441c87e6b5421bcf2bab00d1477b Mon Sep 17 00:00:00 2001 From: Tamo Date: Tue, 17 Jun 2025 17:38:29 +0200 Subject: [PATCH 22/24] fmt --- src/tests/fit_in_memory.rs | 16 +++++++++------- src/tests/mod.rs | 2 +- src/writer.rs | 6 +----- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/tests/fit_in_memory.rs b/src/tests/fit_in_memory.rs index 52521cf..1488f4d 100644 --- a/src/tests/fit_in_memory.rs +++ b/src/tests/fit_in_memory.rs @@ -1,6 +1,6 @@ -use crate::writer::fit_in_memory; -use crate::distances::Euclidean; use crate::distance::Distance; +use crate::distances::Euclidean; +use crate::writer::fit_in_memory; use rand::rngs::StdRng; use rand::SeedableRng; use roaring::RoaringBitmap; @@ -50,23 +50,25 @@ fn test_partial_fit() { fn test_random_selection() { let mut rng = StdRng::seed_from_u64(24); let bitmap = RoaringBitmap::from_sorted_iter(0..1000).unwrap(); - + let dimensions = 128; let largest_item_size = Euclidean::size_of_item(dimensions); let memory = largest_item_size * 500; // Get first batch let mut bitmap_clone = bitmap.clone(); - let result1 = fit_in_memory::(memory, &mut bitmap_clone, dimensions, &mut rng).unwrap(); + let result1 = + fit_in_memory::(memory, &mut bitmap_clone, dimensions, &mut rng).unwrap(); assert!(result1.len() > dimensions as u64); assert_eq!(1000, bitmap_clone.len() + result1.len()); - + // Get second batch let mut bitmap_clone = bitmap.clone(); - let result2 = fit_in_memory::(memory, &mut bitmap_clone, dimensions, &mut rng).unwrap(); + let result2 = + fit_in_memory::(memory, &mut bitmap_clone, dimensions, &mut rng).unwrap(); assert!(result2.len() > dimensions as u64); assert_eq!(1000, bitmap_clone.len() + result2.len()); - + // Batch must be different because of random selection but they must contains the same number of items assert_eq!(result1.len(), result2.len()); assert_ne!(result1, result2); diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 69c88f7..94069bd 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -12,11 +12,11 @@ use crate::version::VersionCodec; use crate::{Database, Distance, MetadataCodec, NodeCodec, NodeMode, Reader}; mod binary_quantized; +mod fit_in_memory; mod reader; mod tmp_nodes; mod upgrade; mod writer; -mod fit_in_memory; pub struct DatabaseHandle { pub env: Env, diff --git a/src/writer.rs b/src/writer.rs index 0b38996..0b80fc9 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1481,11 +1481,7 @@ pub(crate) fn fit_in_memory( dbg!(&nb_items); // We must insert at least dimensions items to create a split - let nb_items = if nb_items <= dimensions { - dimensions + 1 - } else { - nb_items - }; + let nb_items = if nb_items <= dimensions { dimensions + 1 } else { nb_items }; if nb_items as u64 >= to_insert.len() { return Some(std::mem::take(to_insert)); From 29bc623163e276f26038281cd4baee563d142b4b Mon Sep 17 00:00:00 2001 From: Tamo Date: Wed, 18 Jun 2025 11:17:23 +0200 Subject: [PATCH 23/24] Update src/writer.rs Co-authored-by: Many the fish --- src/writer.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/writer.rs b/src/writer.rs index 0b80fc9..1e511d8 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1478,7 +1478,6 @@ pub(crate) fn fit_in_memory( nb_page_allowed }; - dbg!(&nb_items); // We must insert at least dimensions items to create a split let nb_items = if nb_items <= dimensions { dimensions + 1 } else { nb_items }; From e0d18a0b451ac0444c4b30e28c5f247eca769140 Mon Sep 17 00:00:00 2001 From: Tamo Date: Wed, 18 Jun 2025 11:20:26 +0200 Subject: [PATCH 24/24] fmt --- src/writer.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/writer.rs b/src/writer.rs index 1e511d8..fdf2778 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -1478,7 +1478,6 @@ pub(crate) fn fit_in_memory( nb_page_allowed }; - // We must insert at least dimensions items to create a split let nb_items = if nb_items <= dimensions { dimensions + 1 } else { nb_items };