A Lightweight Incremental KD-Tree for Robotic Applications
likd-tree is a lightweight incremental KD-tree designed for dynamic point insertion with automatic rebalancing.
Inspired by ikd-tree, likd-tree is completely reimplemented using modern C++17 and features a more intelligent and principled rebalance strategy, which significantly improves efficiency while keeping the structure lightweight and easy to maintain.
The python version likd-tree is also available now!π
To the best of our knowledge, this is the first Python KD-tree library that supports incremental insertion with automatic rebuilding. Install it via PyPI:
pip install likd-treeFor details see Python Usage
- π Incremental: Dynamic point insertion with automatic background rebalancing
- πͺΆ Lightweight: Header-only library (~450 lines of clean C++17) - no build required
- β‘ Fast: 2.44x faster incremental insertion than ikd-tree
- π§ Intelligent: Smarter rebalance strategy with delayed and batched rebuilding of multiple non-overlapping unbalanced subtrees (paper-worthy?)
- π§ Flexible: Support for custom point types via PointTraits template - use any point representation (arrays, getters, etc.)
Benchmark on 100K random 3D points (Intel CPU, -O3 optimization, with TBB parallel execution):
| Metric | likd-tree | ikd-tree | Speedup |
|---|---|---|---|
| Build Time | 23.70 ms | 36.70 ms | 1.55x |
| Query Time (1000 queries) | 1.23 ms | 1.30 ms | 1.06x |
100K points inserted in batches of 1000:
| Metric | likd-tree | ikd-tree | Speedup |
|---|---|---|---|
| Total Insert Time | 84.04 ms | 151.82 ms | 1.81xβ |
| Total Query Time | 17.37 ms | 71.38 ms | 4.11xβ |
cmake -B build -DBUILD_BENCHMARK=ON
cmake --build build
./build/benchmarkSimply include likd_tree.hpp in your project - no build or installation needed!
#include <pcl/point_types.h>
// Define LIKD_TREE_USE_TBB BEFORE including the header to enable TBB parallel acceleration
#define LIKD_TREE_USE_TBB
#include "likd_tree.hpp"
using PointType = pcl::PointXYZ;
// Create tree
KDTree<PointType> tree;
// Build with initial points
PointVector<PointType> points = {...};
tree.build(points);
// Add more points incrementally
PointVector<PointType> new_points = {...};
tree.addPoints(new_points);
// Batch nearest neighbor queries
PointVector<PointType> queries = {...};
PointVector<PointType> results;
std::vector<float> distances;
tree.nearestNeighbors(queries, results, distances);To enable TBB parallel acceleration:
- Add
#define LIKD_TREE_USE_TBBbefore includinglikd_tree.hpp - Link against TBB library in your build system (CMakeLists.txt or build script)
To disable TBB (sequential execution):
- Simply don't define
LIKD_TREE_USE_TBB, or comment it out
likd-tree supports arbitrary point types through the PointTraits template. By default, it works with point types that have x, y, z members, but you can easily customize it:
// Your custom point type using an array
struct MyPoint {
float coords[3];
};
// Specialize PointTraits for your point type
template <>
struct PointTraits<MyPoint> {
static constexpr int DIM = 3; // your custom point dimensionality
static inline float coord(const MyPoint& pt, int axis) {
return pt.coords[axis];
}
static inline float sqrDist(const MyPoint& a, const MyPoint& b) {
float dx = a.coords[0] - b.coords[0];
float dy = a.coords[1] - b.coords[1];
float dz = a.coords[2] - b.coords[2];
return dx * dx + dy * dy + dz * dz;
}
};
// Use it like any other point type
KDTree<MyPoint> tree;For detailed examples with different point representations (arrays, getters, etc.), see test/demo.cpp.
Install via PyPI:
pip install likd_treeUsage:
import numpy as np
from likd_tree import KDTree
# Create and build tree
points = np.random.rand(10000, 3).astype(np.float32)
tree = KDTree()
tree.build(points)
# Query nearest neighbors
queries = np.random.rand(100, 3).astype(np.float32)
distances, indices = tree.nearest_neighbors(queries)
# Add more points incrementally
new_points = np.random.rand(1000, 3).astype(np.float32)
tree.add_points(new_points)
print(f"Tree size: {tree.size()}")git clone https://github.com/scomup/likd-tree.git
cd likd-tree
cmake -B build
cmake --build build
./build/demogit clone https://github.com/scomup/likd-tree.git
cd likd-tree
cmake -B build -DBUILD_BENCHMARK=ON
cmake --build build
./build/benchmarkIncremental add points without rebalance
Incremental add points with automatic rebalance
Note: Benchmarks and demos require CMake to compile, but the library itself is pure header-only and needs no build step for integration into your project.
Planned Features:
- Node deletion support (Node deletion not supported now)
- k-nearest neighbors (k-NN) query
- box/radius queries
Note: If you require these features immediately, consider using ikd-tree instead.