KD-drzewa

Geometria Obliczeniowa - projekt









Bartłomiej Szczepanik

agenda


  • Problemy wyszukiwania
  • Rozwiązanie w 1D
  • Drzewo czwórkowe - dwie wersje
  • KD-drzewo
    • budowa
    • wyszukiwanie punktów w przedziale
    • wyszukiwanie najblizszego sąsiada
    • dodawanie, usuwanie, balancing
  • Demo

problemy wyszukiwania

  • Find - czy punkt znajduje się w zbiorze
  • Nearest Neighbour - najblizszy punkt 
    od podanego w zbiorze
  • Range Query - wyszukiwanie punktów
    w zadanym przedziale
    (niekoniecznie prostokątnym)
  • Ray Shooting - mając dany promień,
    jaki obiekt pierwszy zostanie
    trafiony przez ten promień

Zastosowania



  • wyszukiwanie kolizji
  • zapytania w bazie danych
  • raytracing
  • wyswietlanie sceny 3D
  • regresja/machine learning

Jeden wymiar


Sortowanie + wyszukiwanie binarne

JEDEN WYMIAR


(statyczne) drzewo przedziałowe 


Jeden wymiar



Jak to uogólnić?

drzewa czwórkowe


Drzewa czwórkowe


drzewa czwórkowe


Wady:
  • słaba skalowalnosc na
    większą liczbę wymiarów (3 max)
  • większa zajętosc pamięci
  • wiele niepotrzebnych przedziałów
  • nie adaptuje się do dystrybucji punktów

Drzewa czwórkowe


Wersja punktowa


kd-drzewo - idea

Drzewo przedziałowe 
dzielące cyklicznie po kolejnych wymiarach

kd-drzewo - Budowa


def buildTree(points, axis):
        if len(points) == 1:
                return Node(points[0])
         
        median = math.median(points, itemgetter(axis))
        left, right = splitBy(points, median, axis)

        node = Node(median)
        node.left = buildTree(leftPoints, (axis + 1) % 2)
        node.right = buildTree(rightPoints, (axis + 1) %2)
        return node;

kd-drzewo - budowa


Koszt:

Wyszukiwanie mediany: O(n)

Całosc:
T(n) = 2T(n/2) + O(n)
T(n) = O(n log n)

wyszukiwanie przedzialu

def processChild(child, range):
       if range.fullyContains(child.range):
                    return root.getWholeSubtreeAsList()
        elif range.intersects(child.range):
                    return search(child, range)

def search(root, range):
        if  root.leaf:
                  return [root.point]  if range.contains(root.point)
                                                                      else []
        return  processChild(root.left, range) + 
                            processChild(root.right, range) 

wyszukiwanie przedzialu

Koszt
T(n) = 2T(n/4)
T(n) = n^(1/2)

W ogólnosci (d -wymiarowe drzewo):
T(n) = 2^(d-1) T(n / 2^d)
T(n) = n^(1-1/d)

Problem czuły na rozwiązanie:
T(n,k) = n^(1/2) + k

Sprawdzanie przynaleznosci
 punktu do zbioru



Sprowadza się do
pytania o przedział [x,y]-[x,y]

T(n) = log n

Wyszukiwanie najblizszego
sasiada




T(n) = log n

wstawianie, usuwanie
Balancing



Wstawianie, usuwanie - identycznie jak w BST
Balancing - tricky!

kd-drzewo - wady




  • da się szybciej
  • curse of dimensionality




DEMO

Podsumowanie





Pytania?

Podsumowanie






Dziękuje za uwagę!

KDdrzewa

By mequrel

KDdrzewa

  • 1,912