Питання: Що ми знаємо про відстань Геммінга d (x, y)?
Відповідь:
- Він невід’ємний: d (x, y) ≥ 0
- Для ідентичних входів це лише нуль: d (x, y) = 0 ⇔ x = y
- Це симетрично: d (x, y) = d (y, x)
- Він виконує нерівність трикутника , d (x, z) ≤ d (x, y) + d (y, z)
Питання: Чому нам все одно?
Відповідь: Оскільки це означає, що відстань Хеммінга є метрикою для метричного простору . Існують алгоритми індексації метричних просторів.
Ви також можете знайти алгоритми "просторової індексації" загалом, озброївшись знанням того, що ваш простір не є евклідовим, а є метричним простором. Багато книг на цю тему охоплюють індексацію рядків за допомогою такої метрики, як відстань Хеммінга.
Примітка: Якщо ви порівнюєте відстань Хеммінга рядків фіксованої ширини, ви можете отримати значне покращення продуктивності, використовуючи вбудовані компоненти або процесор. Наприклад, за допомогою GCC ( вручну ) ви робите це:
static inline int distance(unsigned x, unsigned y)
{
return __builtin_popcount(x^y);
}
Якщо ви потім повідомили GCC, що компілюєте для комп’ютера з SSE4a, то, я вважаю, це повинно зменшитися лише до декількох кодів операційних кодів.
Редагувати: згідно з низкою джерел, це іноді / часто повільніше, ніж звичайний код маски / зміни / додавання. Бенчмаркинг показує, що в моїй системі версія C перевищує GCC __builtin_popcount
приблизно на 160%.
Додаток: Мені самому було цікаво про проблему, тому я сформулював три реалізації: лінійний пошук, дерево BK та дерево VP. Зверніть увагу, що дерева VP і BK дуже схожі. Діти вузла в дереві BK - це «оболонки» дерев, що містять точки, кожна з яких знаходиться на фіксованій відстані від центру дерева. Вузол у дереві VP має двох дочірніх організацій, одна з яких містить усі точки у сфері, центрованій в центрі вузла, а інша дочірня частина, що містить усі точки зовні. Отже, ви можете уявити вузол VP як вузол BK з двома дуже товстими «оболонками» замість багатьох тонших.
Результати були записані на моєму ПК з тактовою частотою 3,2 ГГц, і алгоритми не намагаються використовувати кілька ядер (що повинно бути легко). Я вибрав базу даних розміром 100 млн псевдовипадкових цілих чисел. Результати - це середнє значення 1000 запитів на відстань 1..5 та 100 запитів на 6..10 та лінійний пошук.
- База даних: 100 млн псевдовипадкових цілих чисел
- Кількість тестів: 1000 на відстань 1..5, 100 на відстань 6..10 та лінійні
- Результати: Середнє число звернень за запитом (дуже приблизне)
- Швидкість: кількість запитів в секунду
- Покриття: Середній відсоток перевіреної бази даних за запитом
- BK Tree - - Дерево VP - - Лінійне -
Dist Результати Швидкість Cov Швидкість Cov Швидкість Cov
1 0,90 3800 0,048% 4200 0,048%
2 11 300 0,68% 330 0,65%
3130 56 3,8% 63 3,4%
4970 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-дерева можна вдосконалити, створивши купу BK-дерев з різними кореневими вузлами та розповсюдивши їх.
Я думаю, що це саме причина, чому дерево VP працює (трохи) краще, ніж дерево BK. Будучи "глибшим", а не "більш дрібним", він порівнює порівняно з більшою кількістю точок, а не використовує детальніше порівняння проти меншої кількості точок. Я підозрюю, що відмінності є більш екстремальними у просторах вищих розмірів.
Останній підказка: вузли листів у дереві повинні бути просто плоскими масивами цілих чисел для лінійного сканування. Для невеликих наборів (можливо, 1000 точок або менше) це буде швидше та ефективніше пам’яті.