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
900
俺の 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.7k
【STUDDi】WebGL で学ぶ 3D Graphics の概略
u1roh
0
1.3k
Graph in Rust with unsafe
u1roh
2
1.2k
Other Decks in Programming
See All in Programming
Amazon Bedrock Agentsを用いてアプリ開発してみた!
har1101
0
300
Jakarta Concurrencyによる並行処理プログラミングの始め方 (JJUG CCC 2024 Fall)
tnagao7
1
270
Compose 1.7のTextFieldはPOBox Plusで日本語変換できない
tomoya0x00
0
170
外部システム連携先が10を超えるシステムでのアーキテクチャ設計・実装事例
kiwasaki
1
280
Hotwire or React? ~アフタートーク・本編に含めなかった話~ / Hotwire or React? after talk
harunatsujita
1
110
【Kaigi on Rails 2024】YOUTRUST スポンサーLT
krpk1900
1
310
Duckdb-Wasmでローカルダッシュボードを作ってみた
nkforwork
0
110
僕がつくった48個のWebサービス達
yusukebe
20
17k
C++でシェーダを書く
fadis
6
3.9k
CSC509 Lecture 12
javiergs
PRO
0
140
ActiveSupport::Notifications supporting instrumentation of Rails apps with OpenTelemetry
ymtdzzz
1
180
Generative AI Use Cases JP (略称:GenU)奮闘記
hideg
0
190
Featured
See All Featured
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.1k
A Modern Web Designer's Workflow
chriscoyier
693
190k
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
What's new in Ruby 2.0
geeforr
343
31k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
191
16k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
231
17k
How to train your dragon (web standard)
notwaldorf
88
5.7k
Bootstrapping a Software Product
garrettdimon
PRO
305
110k
The World Runs on Bad Software
bkeepers
PRO
65
11k
Optimizing for Happiness
mojombo
376
69k
Rails Girls Zürich Keynote
gr2m
93
13k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
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