[解決済み] 大規模な集合においてハミング距離の小さい2値文字列を効率的に探索する方法
質問
問題です。
大きな(~1億)符号なし32ビット整数のリストと、符号なし32ビット整数の入力値、そして最大の ハミング距離 が与えられた場合、入力値から指定されたハミング距離の範囲内にある全てのリストメンバーを返します。
リストを保持する実際のデータ構造はオープンで、パフォーマンス要件はインメモリソリューションを指示し、データ構造を構築するコストは二の次で、データ構造をクエリするための低コストは重要です。
例
For a maximum Hamming Distance of 1 (values typically will be quite small)
And input:
00001000100000000000000001111101
The values:
01001000100000000000000001111101
00001000100000000010000001111101
should match because there is only 1 position in which the bits are different.
11001000100000000010000001111101
should not match because 3 bit positions are different.
今までの感想。
ハミング距離が0である縮退したケースについては、ソートされたリストを使用し、特定の入力値についてバイナリ検索を行うだけです。
ハミング距離が1しかない場合は、元の入力の各ビットを反転させ、上記を32回繰り返せばよい。
ハミング距離 >1を持つリストメンバーを(リスト全体をスキャンすることなく)効率的に発見するにはどうしたらよいでしょうか。
どのように解決するのですか?
質問です。 ハミング距離d(x,y)について、私たちは何を知っていますか?
答えてください。
- 非負である:d(x,y) ≥ 0
- 同一の入力に対してのみ0となる:d(x,y) = 0 ⇔ x = y
- 対称である:d(x,y) = d(y,x)
- に従う。 三角形の不等式 , d(x,z) ≦ d(x,y) + d(y,z)
質問です。 なぜ私たちは気にするのでしょうか?
答えてください。 なぜなら、ハミング距離というのは メトリック のための メトリック空間 . メトリック空間をインデックス化するアルゴリズムがあります。
また、空間がユークリッドでなく、一般的な空間インデックスのアルゴリズムも調べることができます。 です。 であることを知った上で、一般的な空間インデックスのアルゴリズムを調べることもできます。 この主題に関する多くの書籍は、ハミング距離のようなメトリックを使用した文字列インデックスの作成について扱っています。
脚注です。 固定幅の文字列のハミング距離を比較する場合、アセンブリやプロセッサの intrinsics を使用することで、大幅な性能向上が得られる可能性があります。 たとえば、GCC で ( マニュアル ) では、このようにします。
static inline int distance(unsigned x, unsigned y)
{
return __builtin_popcount(x^y);
}
もし、SSE4aを搭載したコンピュータ用にコンパイルしていることをGCCに知らせれば、2つのオペコードに減らすことができると思います。
編集します。
多くのソースによると、これは通常の mask/shift/add コードよりも時々/しばしば遅くなるそうです。 ベンチマークによると、私のシステム上では、CバージョンはGCCの
__builtin_popcount
を約 160% 上回っています。
追記です。 私自身この問題に興味があったので、線形探索、BKツリー、VPツリーの3つの実装をプロファイリングしてみました。 VP ツリーと BK ツリーは非常によく似ていることに注意してください。 BK木のノードの子は、木の中心からそれぞれ一定の距離にある点を含む木の殻です。 VP木のノードは、ノードの中心を中心とする球の中にあるすべての点を含む子と、その外側にあるすべての点を含む子の2つの子を持つ。 つまり、VPノードは、多数の細かい殻ではなく、2つの非常に厚い殻を持つBKノードと考えることができます。
結果は私の 3.2 GHz PC でキャプチャされ、アルゴリズムはマルチコアを利用しようとはしません (これは簡単なはずです)。 データベース サイズは 100M の擬似ランダム整数を選択しました。 結果は、距離 1 ~ 5 については 1000 クエリ、6 ~ 10 および線形探索については 100 クエリの平均です。
- データベース 100M個の疑似乱数整数
- テストの数 距離1~5で1000回、距離6~10で100回、線形で100回
- 結果 クエリヒットの平均値 (非常に概算)
- 速度:1秒あたりのクエリ数
- カバレッジ。クエリごとに検査されるデータベースの平均割合
-- BKツリー -- -- VPツリー -- -- 線形 Dist 結果 速度 Cov 速度 Cov 速度 Cov 1 0.90 3800 0.048% 4200 0.048% 2 11 300 0.68% 330 0.65% 3 130 56 3.8% 63 3.4% 4 970 18 12% 22 10% 5 5700 8.5 26% 10 22% 6 2.6e4 5.2 42% 6.0 37% 7 1.1e5 3.7 60% 4.1 54% 8 3.5e5 3.0 74% 3.2 70% 9 1.0e6 2.6 85% 2.7 82% 10 2.5e6 2.3 91% 2.4 90% いずれか 2.2 100
コメントで、こうありました。
BK-treeは、ルートノードの異なるBK-treeを大量に生成して、それを分散させれば改善されると思うのですが。
これはまさに、VPツリーがBKツリーより(少し)良いパフォーマンスをする理由だと思います。 浅い」のではなく「深い」ので、より少ないポイントに対してより細かい比較を行うのではなく、より多くのポイントに対して比較を行います。 高次元の空間では、その差はより極端になるのではないかと思います。
最後のヒント: ツリーのリーフ ノードは、線形スキャンでは単に整数のフラット配列であるべきです。 小さなセット (おそらく 1000 ポイント以下) では、この方が高速でメモリ効率もよいでしょう。
関連
-
[解決済み】Quickselectの時間の複雑さを説明する
-
[解決済み】クイックソートとヒープソートの比較
-
[解決済み】決定木(比較ソートアルゴリズム)の葉の最短の深さ)
-
[解決済み] 定数時間や対数時間よりも、nやnlog(n)の方が良いのでしょうか?
-
[解決済み] 簡単:T(n)=T(n-1)+nを反復法で解く。
-
[解決済み] CLRSの相対的漸近成長に関する問題(表)の解き方について教えてください。
-
[解決済み】画像を使った迷路の表現と解き方
-
[解決済み] リストの並べ換えをすべて生成するアルゴリズム?
-
[解決済み] luceneはどのように文書をインデックスするのですか?
-
[解決済み] 三角関数の仕組み [クローズド]
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] NPとco-NPの違いは何ですか?
-
[解決済み] どのようにすれば、ほとんどすべてのアルゴリズムを修正して、最良の場合の実行時間を持つようにできるか?
-
[解決済み] DPLLアルゴリズムはどのように動作しますか?[クローズド]
-
[解決済み] は、「減少しない」列が「増加する」のか?
-
[解決済み] グラフが半連結であるか否かを判定する
-
[解決済み] 最小ボトルネックスパニングツリーと最小スパニングツリーはどう違うのですか?
-
[解決済み] ヒューリスティックとアルゴリズムの違いは何ですか?
-
[解決済み] LR、SLR、LALRパーサーの違いは何ですか?
-
[解決済み] ビット単位で、モジュラス演算子の代わりに使用
-
[解決済み] 学校の時間割を作成するアルゴリズム