Вычислительная геометрия

Geometric Algorithms at Scale

Uber обрабатывает 28 миллионов GPS-точек в минуту от водителей по всему миру. Google Maps содержит миллиард полигонов зданий и хочет за 100 миллисекунд показать те, что попадают в текущий экран. Здравоохранение Великобритании за пандемию обработало триллион пар контактов через Bluetooth - геометрических близостей. Все эти системы упёрлись бы в стену линейного скана при наивной реализации; именно структуры R-tree, spatial hashing и GPU-параллелизм превращают вычислительную геометрию из учебной дисциплины в производственную инфраструктуру. Без них современная картография, ride-sharing и логистика были бы технически невозможны.

  • **PostGIS / MongoDB / ElasticSearch:** R-tree (GiST/2dsphere) индексы поверх миллиардов записей с миллисекундным поиском
  • **NVIDIA OptiX / Unreal Lumen:** GPU BVH строится на каждый кадр для трассировки лучей в сценах с миллионами треугольников
  • **Apache Sedona / Databricks Mosaic:** distributed spatial-joins на petabyte-данных в реальных пайплайнах Geo BI

R-tree: пространственная индексация больших данных

Линейный скан по миллиарду точек или полигонов - неприемлем. PostGIS, MongoDB GeoSpatial, ElasticSearch Geo, SAP HANA Spatial - все используют R-tree (Antonin Guttman, 1984). Это сбалансированное B-дерево для прямоугольников: каждый внутренний узел хранит минимальный ограничивающий прямоугольник (MBR), охватывающий все его потомки. Поиск range query идёт сверху вниз, отсекая поддеревья, чьи MBR не пересекают целевую область. Высота дерева O(log_M N) при M детях на узел и N листьях, что даёт логарифмический поиск независимо от размерности (2D, 3D, 4D пространственно-временные данные).

Качество R-tree определяется стратегией вставки и расщепления. Guttman оригинально предложил quadratic split - O(N^2), R*-tree (Beckmann, 1990) использует heuristic-минимизацию overlap и dead space, что улучшает поиск на 30-40%. Hilbert R-tree (Kamel-Faloutsos, 1994) упорядочивает прямоугольники по Hilbert-кривой - даёт пространственно-locality для bulk loading. PostGIS GiST-индекс - реализация R*-tree поверх generalized search tree. Для статичных данных bulk loading через STR (Sort-Tile-Recursive) даёт оптимальное packing.

Почему R-tree остаётся стандартом для пространственной индексации, а не KD-tree, который проще?

Spatial Hashing: грид как быстрая альтернатива дереву

R-tree оптимален при разнообразии размеров объектов и низком обновлении. Для динамических систем (физика игр, симуляция жидкостей, чат-приложения с геолокацией пользователей) спортивно используется spatial hashing: разбить пространство на однородный грид, для каждой ячейки хранить список объектов внутри. Поиск точек в радиусе R сводится к проверке O((R/cell)^d) ячеек - константа при фиксированном размере ячейки. Обновление позиции - один remove + один insert: O(1). Игровые движки Box2D и Bullet используют spatial hash для broad-phase collision detection. Uber использует geo-hashing (вариант spatial hash) для поиска ближайших водителей.

Grid resolution - ключевая настройка. Слишком крупная ячейка - проверка тысячи кандидатов; слишком мелкая - один объект попадает в десятки ячеек. Эмпирическое правило: средний размер ячейки ~ средний размер объекта. Hierarchical spatial hash - две сетки разного разрешения для объектов разных размеров. Geohash (Niemeyer, 2008) - кодирование (lat, lon) в строку: соседние ячейки имеют общий префикс, что позволяет хранить пространственные данные в Redis ZSET, MongoDB, Cassandra без специальных индексов.

Когда spatial hashing предпочтительнее R-tree?

GPU-параллелизм: геометрия как dataflow

Современный GPU - тысячи потоков, выполняющих один и тот же шейдер над разными данными (SIMT). Геометрические алгоритмы естественно ложатся на эту модель: вершинный шейдер обрабатывает каждую вершину независимо, fragment shader - каждый пиксель, compute shader - произвольную задачу. Convex hull, Delaunay triangulation, Voronoi diagrams - всё имеет эффективные GPU-реализации. CUDA-библиотеки cugraph, cuSpatial и RAPIDS дают спатиальные операции на datasets в миллиарды точек за секунды. NVIDIA OmniGraph и Unreal Niagara строят рендеринг частиц поверх GPU spatial queries.

Ключевые паттерны GPU-геометрии: parallel scan (prefix sum) для агрегации, parallel reduction для min/max/argmin, parallel sort для упорядочивания по Morton-кодам, atomic operations для конфликтов записи. GPU-grid и GPU-hash - расширения spatial hashing на GPU: ключи через atomicAdd, корзины параллельно. Главный bottleneck - memory bandwidth и divergence: ветвление if/else в шейдере останавливает warp, поэтому стараются избегать data-dependent branches.

Что делает Morton-код (space-filling curve) полезным на GPU?

Параллельные алгоритмы: divide-and-conquer на больших данных

Когда даже GPU не справляется, в дело вступают распределённые системы: Spark, Dask, Ray, Apache Sedona (бывший GeoSpark) обрабатывают пространственные данные на сотнях нодов. Ключевая техника - пространственное партиционирование: разделить плоскость на регионы (R-tree, KD-tree, quad-tree partitioning) так, чтобы каждый воркер обрабатывал свой регион независимо. Затем boundary objects обрабатываются отдельным merge-шагом. Это map-reduce, но с геометрической локальностью. Convex hull на миллиарде точек: parallel sort + Andrew's monotone chain на сегментах + merge - линейная масштабируемость до сотен нодов.

Apache Sedona расширяет Spark SQL пространственными функциями: ST_Contains, ST_Distance, ST_Intersects работают на distributed dataframes. Spatial join (найти все пары полигонов, пересекающиеся пространственно) - типовая O(N*M) операция - сводится к O((N+M) log N) через R-tree partitioning + nested-loop в каждом партишене. Google BigQuery GIS, Amazon Redshift Spatial, Databricks Mosaic - коммерческие реализации той же модели на petabyte-данных.

При больших данных хватит распараллелить наивный O(N^2)-алгоритм - сотня нодов справится

На петабайтных данных линейная масштабируемость требует структурных алгоритмов с правильной локальностью; параллелизм не превращает O(N^2) в O(N log N)

Распараллеленный O(N^2) на P нодах даёт O(N^2 / P) - всё равно квадратично. При N=10^9 это 10^18/100 = 10^16 операций - годы вычислений. Нужны алгоритмы с правильной асимптотикой (R-tree partitioning, Morton-sort, BVH), которые сначала добиваются O(N log N) последовательно, и только потом распараллеливаются на P нодах с эффективностью

Почему пространственное партиционирование критично для distributed spatial join?

Ключевые идеи

  • **R-tree - стандарт пространственной индексации:** сбалансированное B-дерево для прямоугольников, основа PostGIS/MongoDB/ES.
  • **Spatial hashing** выигрывает на динамических данных: O(1) update против O(log N) в R-tree, идеально для физики и геолокации.
  • **GPU-геометрия через Morton-коды** даёт coalesced memory access и параллельное построение BVH за O(N) на тысячах потоков.
  • **Distributed spatial joins** требуют пространственного партиционирования, а не hash-партишена, иначе shuffle становится O(N*M).

Связанные темы

Масштабируемая геометрия объединяет идеи структур данных, GPU-вычислений и распределённых систем.

  • Robotics и GIS — Те же R-tree и spatial hashing используются для path planning и GIS-запросов
  • Распределённые системы: партиционирование — Пространственное партиционирование - аналог consistent hashing для геометрии

Вопросы для размышления

  • R-tree оптимален для статичных данных, spatial hashing - для динамических. Где проходит граница, после которой имеет смысл иметь обе структуры одновременно?
  • GPU-геометрия экономит порядки времени, но требует переписать код под shaders/CUDA. В каких условиях команда выберет хорошо настроенный CPU R-tree вместо GPU BVH?
  • Distributed spatial join работает на петабайтах, но настройка spatial partitioner - нетривиальна. Какие практики помогают подобрать grid resolution и sample rate для R-tree partitioning?

Связанные уроки

  • cgeom-09 — Range trees и k-d деревья - основа для масштабируемых геометрических запросов
  • cgeom-11 — Триангуляция Делоне - базовая структура для пространственных индексов
  • ds-16-graphs-intro — Геометрические графы (k-NN graph) - стандартный инструмент
  • alg-14-dijkstra — A* - это Dijkstra с геометрической эвристикой
  • par-01
Geometric Algorithms at Scale

0

1

Войти