Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
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.3k
Other Decks in Programming
See All in Programming
Ruby×iOSアプリ開発 ~共に歩んだエコシステムの物語~
temoki
0
340
GitHubとGitLabとAWS CodePipelineでCI/CDを組み比べてみた
satoshi256kbyte
4
240
速いWebフレームワークを作る
yusukebe
5
1.7k
複雑なフォームに立ち向かう Next.js の技術選定
macchiitaka
2
180
CJK and Unicode From a PHP Committer
youkidearitai
PRO
0
110
OSS開発者という働き方
andpad
5
1.7k
Testing Trophyは叫ばない
toms74209200
0
890
Oracle Database Technology Night 92 Database Connection control FAN-AC
oracle4engineer
PRO
1
460
The Past, Present, and Future of Enterprise Java with ASF in the Middle
ivargrimstad
0
160
プロパティベーステストによるUIテスト: LLMによるプロパティ定義生成でエッジケースを捉える
tetta_pdnt
0
3.3k
Introducing ReActionView: A new ActionView-compatible ERB Engine @ Rails World 2025, Amsterdam
marcoroth
0
710
HTMLの品質ってなんだっけ? “HTMLクライテリア”の設計と実践
unachang113
4
2.9k
Featured
See All Featured
Build The Right Thing And Hit Your Dates
maggiecrowley
37
2.9k
Rails Girls Zürich Keynote
gr2m
95
14k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4k
Six Lessons from altMBA
skipperchong
28
4k
How to train your dragon (web standard)
notwaldorf
96
6.2k
Art, The Web, and Tiny UX
lynnandtonic
303
21k
Embracing the Ebb and Flow
colly
87
4.8k
Intergalactic Javascript Robots from Outer Space
tanoku
272
27k
Optimising Largest Contentful Paint
csswizardry
37
3.4k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
Designing for Performance
lara
610
69k
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