Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
steps:
- name: Install gtest manually
run: sudo apt-get install libgtest-dev
run: sudo apt install libomp-dev

- uses: actions/checkout@v3

Expand Down
Binary file added doc/topic2/img/SAH.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/topic2/img/raytracing.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/topic2/img/search.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/topic2/img/stop.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/topic2/img/полигон.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/topic2/img/разбиение.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/topic2/img/расстояние.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
78 changes: 78 additions & 0 deletions doc/topic2/question1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# KDTree

Данный конспект является необязательным, но будет интересным для ознакомления
## Что такое KDTree и где используется?
До этого мы рассматривали деревья, работающие в одномерном пространстве. Но бывают случаи, когда необходимо работать в пространстве.
$KDTree$ - это разновидность дерева, применяемого в многомерном пространстве. $K$ в названии указывает на размерность в которой оно реализуется. К примеру существуют 2D-Дерево, 3D-Дерево и тд.


Одна из самых главных задач, которые решает данная структура - это поиск
ближайшей точки (объекта). Данная функция может быть необходима, например, при разработке игр, в частности
в так называемом ray tracing. Сложные 3D модели состоят из многочисленных треугольников и алгоритм обработки изображения требует быстро находить ближайший треугольник к заданой точке, для просчета луча света, проходящего через объект.

![Полигон](img/полигон.jpg)


#### **Cyberpunk 2077 с использованием ray tracing технологии**
![raytracing](img/raytracing.jpg "Cyberpunk 2077 с использованием ray tracing технологии")





Также KD-Дерево используется в Яндекс.Такси для поиска ближайшей свободной машины к заказчику. Здесь тоже нужна скорость, мы же не хотим заставлять клиентов долго ждать

<img src="img/search.png" width="270" height="584.25" >


## Принцип работы

Далее будем говорить о множестве точек на плоскости (порядка миллиона), представляющие собой 2 координаты: x и y. Но стоит помнить, что вместо них могут быть как те же треугольники, так и другие объекты, которые могут находиться не только в плоскости, но и в пространстве, 4-х мерном измерении и тд. Принцип работы координально отличаться не будет, но все же некоторые нюансы стоит учитывать.Однако на них в данном конспекте заострять внимание не будем.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"... учитывать.Однако ..." пробела не хватает



Итак, предположим, что у нас есть набор точек на плоскости. Глобально алгоритм предполагает разбиение данной плоскоти на более мелкии её составляющие. Это нужно, чтобы для поиска ближайшего мы не перебирали каждый раз *все* точки плоскости, а только *часть* из их.

Для разделения мы должны как-то обозначать границы нашей плоскости. Один способов это сделать - использовать так называемый bounding box. По сути это условные прямоугольники, в которые помещаются наши точки. Далее нам нужно как-то разделить наше пространство. Естсетвенно, разбиение, где в одном подпространстве будет 1 точка, а в другом 99999 нас не очень устраивает, так как мы хотим добиться скорости. Таких разбиений стоит избегать и строить дерево более равномерно.

#### Как это можно сделать?
* Один из самых простых способов - использовать случайное распределение. Даст ли это равномерное распределение? Может да, а может и нет :)
* Можно выбирать наиболее длинную сторону bounding box и делить её пополам.
* Рассекать по медиане: отсортируем все точки по одной из координат, а медианой назовем элемент (или центр элемента), который находится на средней позиции в отсортированном списке. Секущая плоскость будет проходить через медиану так, что количество элементов слева и справа будет примерно равным.

Данные способы позволяют быстро построить дерево, но с большой вероятностью оно будет разбито неравномерно, что скажется на скорости основных функций дерева. Поэтому чтобы получить наиболее оптимальный результат данные методы не подойдут. Нужно как-то вычислить оптимальное разбиение. Для этого были придуманы функции, которые оценят выгодность конкретного разбиения. Один из примеров таких функций - $SAH$ (Surface Area Heuristic). О ней мы поговорим чуть позже.

![разбиение](img/разбиение.jpg)

Картинка выше - пример возможного разбиения нашего пространства.

Важно отметить, что для эффективного использования памяти координаты точек необходимо хранить в листьях нашего дерева. Сами узлы должны хранить информацию о своем bounding box.

Итак, у нас есть готовое дерево, теперь рассмотрим алгоритмическую составляющую поиска ближайщего к точке.

Пусть у нас есть координаты точки, к которой мы хотим найди ближайшую. Основная идея заключается в том, чтобы найти сначала ближайший bounding box (BB) к этой точке. Затем, мы перебираем все точки в BB и выбираем точку с минимальным расстояниям. Выбрать BB можно, идя рекурсивно, начиная с корня и проверяя лежит ли наша точка в BB левого поддерева или правого. С таким подходом может быть проблема, если данная точка не лежит в BB всех точек (BB корня дерева). Чтобы учесть это следует проверять принадлежность не самой точки, а части окружности, с центром в данной точке.

Что делать если для нашей точки подходят несколько BB? Такое может случится, если наша точка оказалась на границе раздела. В данном случае мы просто будем проверять все подходящие BB. Вы можете подумать, что это неэффективно, но на самом деле мы проверим небольшое количество BB, в сравнении со всеми точками (даже если получится очень неудачная ситуация и необходимо будет перебрать 100000 точек, это все равно в 10 раз эффективнее перебора 1000000).

![расстояние](img/расстояние.png)


## Подробнее про SAH функцию
Давайте подробнее поговорим про SAH функцию. Как уже было сказано она нужна, чтобы оценить выгодность конкретного разбиения. Её значение вычисляется следующим образом:

![SAH](img/SAH.jpg)

Данная формула взята для случая ray tracing'а, но ее можно использовать и для других целей.

Как же ей пользоваться? Сначала мы выбираем направление (линию Ox или Oy). Затем мы делим наш BB на равные части вдоль выбранного направления. Сколько выбрать таких частей зависит от вашего желания и компромисса скорости построения KDTree и его равномерностью. Достаточно оптимальным можно считать разбинение на 33 части. Затем, каждую из этих частей мы отправляем в нашу SAH функцию. Она расчитывается для каждого из предполагаемых разбиений. Остается только выбрать ту часть, которая имеет наименьшее значение по этой функции. Оно и будет самым выгодным.

Константы $C_i$ и $C_t$ также стоит подбирать из соображений оптимальности построения KDTree и его работоспособностью.
В том же ray tracing'е, откуда была взята данная формула $C_i$ обычно равняется $1$, а $C_t$ находится в пределах $[1,2]$.

Кроме этого с помощью SAH функции можно определить условие остановки построения дерева

![stop](img/stop.jpg)

Прекращаем деление, так как следующее разбиение уже не будет более выгодным

# На этом все
Это была краткая справка о том, что вообще из себя представляет KDTree и какие алгортмы лежат в его реализации. Подробнее о создании данного типа деревьев можно почитать [здесь](https://habr.com/ru/articles/312882/). А также на [википедии](https://ru.wikipedia.org/wiki/K-d-дерево)
23 changes: 23 additions & 0 deletions lib/src/util.cpp
Original file line number Diff line number Diff line change
@@ -1 +1,24 @@
#include "util.hpp"

void MergeSort(std::vector<int>& array) {
int n = array.size();
std::vector<int> buffer(n);

for (int slice = 1; slice < n; slice *= 2) {
for (int left = 0; left < n; left += 2 * slice) {
int mid = std::min(left + slice, n);
int right = std::min(left + 2 * slice, n);

int i = left, j = mid;
int k = left;
while (i < mid && j < right) {
buffer[k++] = array[i] <= array[j] ? array[i++] : array[j++];
}
while (i < mid) buffer[k++] = array[i++];
while (j < right) buffer[k++] = array[j++];

std::copy(buffer.begin() + left, buffer.begin() + right,
array.begin() + left);
}
}
}
3 changes: 3 additions & 0 deletions lib/src/util.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include <vector>

void MergeSort(std::vector<int>& array);
Binary file added sandbox/template/src/main
Binary file not shown.
42 changes: 40 additions & 2 deletions sandbox/template/src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,41 @@
#include <iostream>
// #include <iostream>
// #include <vector>

int main() { return 0; }
// void MergeSort(std ::vector<int>& array) {
// int i{0}, j{1};
// int slice{1};
// do {
// while (j <= array.size() - 1) {
// if (array[i] > array[j]) {
// iter_swap(array.begin() + i, array.begin() + j);

// ++j;
// } else
// ++i;
// if (j - i > slice) {
// i = j;
// j = i + slice;
// } else if (j == i) {
// i += 1;
// j = i + slice;
// }
// }
// slice *= 2;
// slice > array.size() ? j = array.size() - 1 : j = slice;
// i = 0;
// if (j == array.size() - 1) {
// if (i == 0) {
// return;
// }
// }
// } while (true);
// }

int main() {
// std ::vector<int> unsort{3, 2, 4, 5, 1, 9, 7};
// MergeSort(unsort);
// for (int i = 0; i < unsort.size(); ++i) {
// std ::cout << unsort[i] << " ";
// }
// std ::cout << std ::endl;
}
8 changes: 4 additions & 4 deletions sandbox/template/src/test.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

#include <gtest/gtest.h>
// #include <gtest/gtest.h>

#include <stack>
// #include <stack>

#include "utils.hpp"
// #include "utils.hpp"

TEST(Template, Simple) { ASSERT_EQ(true, true); }
// TEST(Template, Simple) { ASSERT_EQ(true, true); }
2 changes: 1 addition & 1 deletion sandbox/template/src/utils.cpp
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#include "utils.hpp"
// #include "utils.hpp"
2 changes: 1 addition & 1 deletion sandbox/template/src/utils.hpp
Original file line number Diff line number Diff line change
@@ -1 +1 @@
#pragma once
// #pragma once
20 changes: 20 additions & 0 deletions task_01/src/find.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include "find.hpp"

std ::vector<int> FindNums(int k, std ::vector<int> sequence) {
if (sequence.size() == 0) throw NoSumNum{};

std ::vector<int> answer;
unsigned long left_index{0};
unsigned long right_index{sequence.size() - 1};
while (left_index != right_index) {
if ((sequence[left_index] + sequence[right_index]) == k) {
answer.push_back(sequence[left_index]);
answer.push_back(sequence[right_index]);
return answer;
} else if (sequence[left_index] + sequence[right_index] > k)
--right_index;
else
++left_index;
}
throw NoSumNum{};
}
8 changes: 8 additions & 0 deletions task_01/src/find.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include <string>
#include <vector>

struct NoSumNum {
std ::string s{"no possible way to solve task"};
};

std ::vector<int> FindNums(int k, std ::vector<int> sequence);
2 changes: 1 addition & 1 deletion task_01/src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#include <iostream>

int main() { return 0; }
int main() { return 0; }
32 changes: 30 additions & 2 deletions task_01/src/test.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
#include <gtest/gtest.h>

TEST(Test, Simple) {
ASSERT_EQ(1, 1); // Stack []
#include "find.hpp"

TEST(FindNums, Simple) {
std ::vector<int> seq{1, 2, 3, 4, 5};
std ::vector<int> ans{FindNums(5, seq)};
ASSERT_EQ(5, ans[0] + ans[1]);
}

TEST(FindNums, Negative) {
std ::vector<int> seq{-100, -10, -9, -8, -1};
std ::vector<int> ans{FindNums(-9, seq)};
ASSERT_EQ(-9, ans[0] + ans[1]);
}

TEST(FindNums, WithZeros) {
std ::vector<int> seq{
-15, 0, 0, 2, 8,
};
std ::vector<int> ans{FindNums(10, seq)};
ASSERT_EQ(10, ans[0] + ans[1]);
}

TEST(FindNums, NoValue) {
std ::vector<int> seq{0, 0, 2, 8, -15};
EXPECT_THROW(FindNums(60, seq), NoSumNum);
}

TEST(FindNums, Empty) {
std ::vector<int> seq(0);
EXPECT_THROW(FindNums(60, seq), NoSumNum);
}
21 changes: 0 additions & 21 deletions task_02/src/stack.cpp

This file was deleted.

67 changes: 57 additions & 10 deletions task_02/src/stack.hpp
Original file line number Diff line number Diff line change
@@ -1,23 +1,70 @@
#pragma once

#include <stack>
#include <concepts>
#include <stdexcept>
#include <vector>

template <typename T>
concept Comparable = requires(T a, T b) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 'T' does not refer to a value [clang-diagnostic-error]

concept Comparable = requires(T a, T b) {
                                   ^
Additional context

task_02/src/stack.hpp:4: declared here

template <typename T>
                   ^

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 'T' does not refer to a value [clang-diagnostic-error]

concept Comparable = requires(T a, T b) {
                              ^
Additional context

task_02/src/stack.hpp:4: declared here

template <typename T>
                   ^

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unknown type name 'concept' [clang-diagnostic-error]

concept Comparable = requires(T a, T b) {
^

{ a < b } -> std::convertible_to<bool>;
};

template <Comparable T>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unknown type name 'Comparable' [clang-diagnostic-error]

template <Comparable T>
          ^

class Stack {
public:
void Push(int value);
int Pop();
void Push(T k);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unknown type name 'T' [clang-diagnostic-error]

  void Push(T k);
            ^

T Pop();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unknown type name 'T' [clang-diagnostic-error]

  T Pop();
  ^


private:
std::stack<int> data_;
std ::vector<T> _data;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: template argument for template type parameter must be a type [clang-diagnostic-error]

  std ::vector<T> _data;
               ^
Additional context

/usr/include/c++/13/bits/stl_vector.h:426: template parameter is declared here

  template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
                    ^

};

template <Comparable T>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unknown type name 'Comparable' [clang-diagnostic-error]

template <Comparable T>
          ^

void Stack<T>::Push(T k) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unknown type name 'T' [clang-diagnostic-error]

void Stack<T>::Push(T k) {
                    ^

_data.push_back(k);
}

template <Comparable T>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unknown type name 'Comparable' [clang-diagnostic-error]

template <Comparable T>
          ^

T Stack<T>::Pop() {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unknown type name 'T' [clang-diagnostic-error]

T Stack<T>::Pop() {
^

if (_data.size() == 0) throw std::out_of_range("No data in stack");
T pop_val{_data.back()};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: expected ';' after expression [clang-diagnostic-error]

Suggested change
T pop_val{_data.back()};
T; pop_val{_data.back()};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: use of undeclared identifier 'pop_val' [clang-diagnostic-error]

  T pop_val{_data.back()};
    ^

_data.pop_back();
return pop_val;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: use of undeclared identifier 'pop_val' [clang-diagnostic-error]

  return pop_val;
         ^

}

template <Comparable T>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unknown type name 'Comparable' [clang-diagnostic-error]

template <Comparable T>
          ^

class MinStack {
public:
void Push(int value);
int Pop();
int GetMin();
void Push(T k);
T Pop();
T GetMin();

private:
std::vector<int> data_;
std ::vector<T> _data;
std ::vector<T> _min_data;
};

template <Comparable T>
void MinStack<T>::Push(T k) {
if (_min_data.size() == 0)
_min_data.push_back(k);
else if (_min_data.back() > k)
_min_data.push_back(k);
else
_min_data.push_back(_min_data.back());
_data.push_back(k);
}

template <Comparable T>
T MinStack<T>::Pop() {
if ((_data.size() == 0) || (_min_data.size() == 0))
throw std::out_of_range("No data in stack");
T pop_val{_data.back()};
_data.pop_back();
_min_data.pop_back();
return pop_val;
}

template <Comparable T>
T MinStack<T>::GetMin() {
if (_min_data.size() == 0) throw std::out_of_range("No data in stack");
return _min_data.back();
}
Loading
Loading