Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
俺の kd-tree
Search
Terada Yuichiro
November 24, 2020
Programming
0
1.2k
俺の kd-tree
Rust で kd-tree を自作し、crates.io に公開しました。kd tree とは?パフォーマンスは? 設計は? といったあたりをまとめた発表資料です。
Terada Yuichiro
November 24, 2020
Tweet
Share
More Decks by Terada Yuichiro
See All by Terada Yuichiro
WebGPU 触ってみた
u1roh
0
1.9k
【STUDDi】WebGL で学ぶ 3D Graphics の概略
u1roh
0
1.4k
Graph in Rust with unsafe
u1roh
2
1.4k
Other Decks in Programming
See All in Programming
手軽に積ん読を増やすには?/読みたい本と付き合うには?
o0h
PRO
1
140
【CA.ai #3】Google ADKを活用したAI Agent開発と運用知見
harappa80
0
250
Media Capture and Streams: W3C仕様と現場での知見
nowaki28
0
130
モダンJSフレームワークのビルドプロセス 〜なぜReactは503行、Svelteは12行なのか〜
fuuki12
0
180
Full-Cycle Reactivity in Angular: SignalStore mit Signal Forms und Resources
manfredsteyer
PRO
0
170
Querying Design System デザインシステムの意思決定を支える構造検索
ikumatadokoro
1
1.2k
【レイトレ合宿11】kagayaki_v4
runningoutrate
0
220
俺流レスポンシブコーディング 2025
tak_dcxi
13
7.6k
全員アーキテクトで挑む、 巨大で高密度なドメインの紐解き方
agatan
8
18k
Google Antigravity and Vibe Coding: Agentic Development Guide
mickey_kubo
2
130
MAP, Jigsaw, Code Golf 振り返り会 by 関東Kaggler会|Jigsaw 15th Solution
hasibirok0
0
210
CSC509 Lecture 14
javiergs
PRO
0
220
Featured
See All Featured
Site-Speed That Sticks
csswizardry
13
990
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
1.6k
Optimising Largest Contentful Paint
csswizardry
37
3.5k
Product Roadmaps are Hard
iamctodd
PRO
55
12k
Large-scale JavaScript Application Architecture
addyosmani
514
110k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
3.8k
A Tale of Four Properties
chriscoyier
162
23k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
1.8k
Rails Girls Zürich Keynote
gr2m
95
14k
Building Adaptive Systems
keathley
44
2.9k
Leading Effective Engineering Teams in the AI Era
addyosmani
8
1.2k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
61k
Transcript
俺の kd-tree 2020-11-24 Y.Terada @ CADDi
自己紹介 • てらだ( @u_1roh ) • CADDi で図面の画像解析 に取り組んでいます。 •
Rust でアルゴリズム、い いですよね!
こんなことを話します • kd-tree を自作して crates.io に publish してみた • そもそも
kd-tree とは? • なぜ自作したの? • どんな実装? • パフォーマンスは?
kd-tree とは • k-dimensional tree • k 次元空間の点群を高速に探索可能にするデータ構造 • こんな探索が出来ます
– 【最近傍探索】点群から、指定座標に最も近い点を探索 – 【 k 近傍探索】近いものから k 個探索( k が被ってる…) – 【領域探索】指定領域に含まれる点を全て探索
kd-tree の構築( 2D の場合) • 2 分木のノードに点をひとつ格納 • X で分割
→ Y で分割 → X で分割 → Y で分割 → … https://www.datasciencecentral.com/profiles/blogs/implementing-kd-tree-for-fast-range-search-nearest-neighbor
最近傍探索 問合せ点 Q この枝における 最近傍点 探索不要な枝 探索済みの枝
crates.io を探すと
使ってみた • `kdtree` – 遅い – 点の逐次追加でツリーを構築するスタイル – 任意次元の kd
tree が作れる – 点座標の数値型は `num_traits::Float` 型(つまり `f64` と `f32`) – 型が `KdTree<f64, T, [f64; 3]>` みたいになる(`f64` を 2回書く) • `fux_kdtree` – 速い( `kdtree` の 2.5〜 3倍) – 点の配列から一気に構築するスタイル – 3次元までしか作れない – 点座標の数値型は `f64` のみ – `fux_kdtree::kdtree::KdtreePointTrait` を実装しないといけない
作りたいもの • `fux_kdtree` 並の速度で、 • 任意次元で使えて、 • 整数値の座標値が扱えて、 • 設計が洗練されているもの
できた!
ベンチマーク(構築処理) fux_kdtree kdtree 俺の (f64) 俺の (i32) [0, 1]^3 の空間に
一様な乱数で 10^n 個の点を生成 10^2 点 10^3 点 10^4 点
ベンチマーク(最近傍探索) fux_kdtree kdtree 俺の (f64) 俺の (i32) 10^2 点 10^4
点 10^3 点
機能はまだ足りない • 最近傍探索しかできない – ◦ 【最近傍探索】指定座標に最も近い点を探索 – ☓ 【 k
近傍探索】近いものから k 個探索 – ☓ 【領域探索】指定領域に含まれる点を全て探索 • 今後、機能追加していきたい
俺の kd-tree 使い方 編
基本のき use kd_tree::KdTree; let items: Vec<[i32; 3]> = vec![[1, 2,
3], [3, 1, 2], [2, 3, 1]]; let kdtree: KdTree<[i32; 3]> = KdTree::build(items); assert_eq!(kdtree.nearest(&[3, 1, 2]).unwrap().item, &[3, 1, 2]); • KdTree<[i32; 3]> ← 型がシンプル! • 整数座標が使える!(※ unsigned はダメ)
f64 の座標を使う • 浮動小数点座標の場合は build_by_ordered_float() を使う。 – f64 は Ord
を実装していないので。 – ordered_float::OrderedFloat を利用 use kd_tree::KdTree; let kdtree: KdTree<[f64; 3]> = KdTree::build_by_ordered_float(vec![ [1.0, 2.0, 3.0], [3.0, 1.0, 2.0], [2.0, 3.0, 1.0] ]); assert_eq!( kdtree.nearest(&[3.1, 0.9, 2.1]).unwrap().item, &[3.0, 1.0, 2.0] );
マップのようにも使えます • KdMap<P,T> … Map のように使える kd tree – P
に点座標 – T には任意の型が入る use kd_tree::KdMap; let kdmap: KdMap<[isize; 3], &'static str> = KdMap::build(vec![ ([1, 2, 3], "foo"), ([2, 3, 1], "bar"), ([3, 1, 2], "buzz"), ]); assert_eq!(kdmap.nearest(&[3, 1, 2]).unwrap().item.1, "buzz");
KdPoint カスタム実装 use kd_tree::{KdPoint, KdTree}; struct Item { point: [f64;
2], id: usize } impl KdPoint for Item { type Scalar = f64; type Dim = typenum::U2; // 2 dimensional tree. fn at(&self, k: usize) -> f64 { self.point[k] } } let kdtree: KdTree<Item> = KdTree::build_by_ordered_float(vec![ Item { point: [1.0, 2.0], id: 111 }, Item { point: [2.0, 3.0], id: 222 }, Item { point: [3.0, 4.0], id: 333 }, ]); assert_eq!(kdtree.nearest(&[1.9, 3.1]).unwrap().item.id, 222);
KdSlice • KdTree のスライス型( String に対する str ) – Sized
ではない → 常に参照型で扱う – KdTree は Deref<Target=KdSlice<...>> を実装 • KdSlice::sort() は items を move しない(ソートするだ け) use kd_tree::KdSlice; let mut items: Vec<[i32; 3]> = vec![[1, 2, 3], [3, 1, 2], [2, 3, 1]]; let kdtree: &KdSlice<[i32; 3]> = KdSlice::sort(&mut items); assert_eq!(kdtree.nearest(&[3, 1, 2]).unwrap().item, &[3, 1, 2]);
俺の kd-tree データ構造 編
バランス良く構築 8 個 8 個 4 個 3 個 4
個 3 個
構築フロー items: &mut [T] x 座標でソート ↑items.len()/2 y 座標でソート ↑items.len()/2
x 座標でソート ↑items.len()/2 このまま実装すると ソートが多いので遅い
Quick select • 必要なのはソートではない – 中央値の左右で要素が分かれていれば良い – 左右それぞれの枝はソートされている必要がない • Quick
select • `pdqselect` クレート • k 番目を境に要素を分ける
`kd_sort_by()`
並び替えるだけで kd tree になる • binary-tree と似ている – [T] を
sort() しておけば binary_search() できる – 同様に、 [T] を並び替えておけば最近傍探索できる • 構築に必要なのは次元と kd_compare だけ – (注:最近傍探索は kd_compare だけでは足りません。距離が測 れないといけないので。) • このシンプルさ&柔軟さを最大限に活かした設計にしたい。
KdSliceN<T, N> pub struct KdSliceN<T, N: Unsigned>(PhantomData<N>, [T]); impl<T, N:
Unsigned> KdSliceN<T, N> { pub fn sort_by<F>(items: &mut [T], compare: F) -> &Self where F: Fn(&T, &T, usize) -> Ordering + Copy, { kd_sort_by(items, N::to_usize(), compare); unsafe { &*(items as *const _ as *const Self) } } } 次元 unsized 参照を返す unsafe を使ってキャスト
KdTreeN<T, N> pub struct KdTreeN<T, N: Unsigned>(PhantomData<N>, Vec<T>); impl<T, N:
Unsigned> KdTreeN<T, N> { pub fn build_by<F>(mut items: Vec<T>, compare: F) -> Self where F: Fn(&T, &T, usize) -> Ordering + Copy, { kd_sort_by(&mut items, N::to_usize(), compare); Self(PhantomData, items) } }
KdPoint
KdPoint の実装
Type aliases pub type KdSlice<T> = KdSliceN<T, <T as KdPoint>::Dim>;
pub type KdTree<T> = KdTreeN<T, <T as KdPoint>::Dim>; pub type KdMap<P, T> = KdTree<(P, T)>; pub type KdMapSlice<P, T> = KdSlice<(P, T)>;
まとめ • 自作 kd-tree を crates.io に公開した • 性能 –
`kdtree` より速い(構築も探索も) – 探索は `fux_kdtree` より速い • 機能 – 整数座標が扱える – 高次元が扱える ※ CADDi では Rust でアルゴリズムを書きたいエンジニアを募集しています
None