LINUX.ORG.RU

[C++] поиск параллепипеда в d-мерной области при помощи std::map?

 


0

3

Есть большой параллелепипед в d-мерном дискретном пространстве. Его разбивают на некоторое кол-во подобластей параллелепипедов (разных размеров), маленькие параллелепипеды не пересекаются, а в большом не остается дыр.

Теперь нужно организовать поиск, т.е. по набору из d целых чисел (точка в d-мерном пространстве) найти соотв. маленький параллелепипед. Поиск должен работать как можно быстрее, актуальные значения d=2,3 число подобластей от сотен до десятков тысяч.

Попробовал перебором - дурацкая затея, и вроде как есть ощущение что можно сюда прикрутить std::map. У меня есть объект индекса indx<D> (точки в этом самом пр-ве) из D чисел, для которого есть правильная std::less

namespace std{
	template< class T > struct less;
	template< int D > struct less<aiv::indx<D> > {
		bool operator()( const aiv::indx<D>& x, const aiv::indx<D>& y ) const { 
			for( int i=D; i>=0; i-- ){
				if( x[i] < y[i] ) return true;
				if( x[i] > y[i] ) return false;
			}
			return false;
		} 
	};
};

Можно сделать структуру

struct indx_cube{ 
 indx<D> min, max; 
 inline bool operator <  ( const indx_cube& other ) const { 
  return std::less< indx<D> >()( max, other.min ); 
  }
};

и юзать indx_cube в качестве ключа map. Вот теперь нападает утренний тупняк - вроде как понятно, что можно таким образом накидать в map параллелепипедов. Но будет ли работать поиск? Скажем мне нужно найти что то по точке indx<D> I. Если я в качестве ключа передам indx_cube(min=I,max=I), че нить разумное получится? Что бы точка попала в подобласть должно быть покомпонентное

min[i]<=I[i] && I[i]<max[i]

Че та не хватает воображения;-(

★★★★★

в вашем случае, когда параллелепипед под-завязку забит другими не пересекающимися параллелепипедами, и когда кол-во подобластей невелико, то есть всего-то до «до десятков тысяч», то можно юзать n-мерный массив. По координатным осям будет нечто переводящее отсортированные отсчёты(проекции вершин) в целочисленный индекс массива, А в самом массиве лежать идентификаторы (указатели) на покрывающую область.

Если например трехмерную область вы разбили на 10000 мелких областей, то кол-во проекций на оси будет в пределах 100х3, и объём массива указателей 4 Мб - вполне подходит для очень быстрой выборки

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

Так вот и вопрос - что это за нечто, переводящее отсчеты в индекс? Я не могу придумать алгоритма, однозначно упорядочивающего области.

AIv ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Разбиение не бинарное.

AIv ★★★★★
() автор топика

Есть большой параллелепипед в d-мерном дискретном пространстве

не уверен, что это параллелепипед имхо.

Теперь нужно организовать поиск, т.е. по набору из d целых чисел (точка в d-мерном пространстве) найти соотв. маленький параллелепипед.

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

mi_estas
()
Ответ на: комментарий от mi_estas

Нет, не правильно. Мне нужно построить такой мап, что бы по ключу (точке в d-мерном дискретном пространстве) получать объект (d-мерный параллелепипед) в который эта точка попала. Число записей в map-е должно быть порядка числа параллелепипедов (десятки тысяч как макс). При этом число возможных точек до 10^10 а может и больше.

AIv ★★★★★
() автор топика

Создать отсортированные массивы по каждой из компонент координаты.
P_0(x0,y0,...,z0),P_1(x1,y1,...,z1),...,P_n(xn,yn,...,zn) Вершины параллелепипедов
a[0]=[P_j,xj],a[1]=[P_k,xk)]..., x_j < x_k Массив по компоненте x, отсортирован
. Берем точку d(x,y,...,z). Находим в каждом массиве набор точек которые удовлетворяют условиям x_j<x<x_k. В результате у нас будет набор параллелепипедов. А пересечение этой выборки как мне кажется должно дать искомый параллелепипед. Сложность порядка n*log(n).

b_a
()
Ответ на: комментарий от AIv

невнимательно читаешь

забить мап точками дискретного пространства, а значениями мапа будут параллелепипеды

foreach (dot, cube) {
   foreach (parallelepiped, parallelepipedsInTheCube) {
       if (parallelepiped.has(dot)) {
       //или if(dot.isIside(paralellepiped)) {
           map.insert(pair<dot, parallelepiped>);
       }
   }
}

как то так. много не думал, может можно улучшить как-то.

mi_estas
()
Ответ на: комментарий от mi_estas

> невнимательно читаешь

map из 10^10 записей? Нафига там map, когда можно взять обычный d-мерный массив, но все равно это не подходит - тогда теряется весь смысел задачи.

AIv ★★★★★
() автор топика
Ответ на: комментарий от b_a

Дать то оно даст, но больно муторно... но спасибо за идею, я о чем то подобном думал, но не формализовал.

AIv ★★★★★
() автор топика
Ответ на: комментарий от nikitos

Разбиение не бинарное может быть. Но я подумаю, спасибо.

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

нечто, переводящее отсчеты в индекс?

например сортированный по значению vector<pair<double,double>> по каждой оси может однозначно переводить отрезки с оси координат на индекс массива за O(ln(n)). За непересечением этих отрезков и уникальностью отсчётов придётся последить самому :)

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

> За непересечением этих отрезков и уникальностью отсчётов придётся последить самому

О чем и речь;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

тут остается только некий вопрос - смежные параллелепипеды могут иметь одинаковые координаты - это тоже нужно учесть. Хотя насколько я понимаю в задаче четкое условие, что точка лежит внутри.

b_a
()
Ответ на: комментарий от AIv

> За непересечением этих отрезков и уникальностью отсчётов придётся последить самому

О чем и речь;-)

какая проблема-то ? несколько строчек кода..добавить значение в сортированный по значению-же вектор и проследить за уникальностью ?

MKuznetsov ★★★★★
()
Ответ на: комментарий от b_a

Не совсем. Точка может лежать где угодно, левая граница параллепипеда включается, правая нет.

AIv ★★★★★
() автор топика
Ответ на: комментарий от MKuznetsov

Хотелось сделать изящно... Я пока склоняюсь к тупому перебору с кэшированием последнего обращения.

AIv ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Прикольно... оказывается частные случаи того, что я в свое время сваял для вычисления функции распределения произвольной размерности, называются Quadtree и Octree;-)

kd tree конечно тема, но уж больно муторный процесс набивки в дааном случае. Может со временем и перейду... пока что буду делать так:

набиваю map боксами, ключом является координата нижнего левого угла.

при поиске для точки с координатами r вызываю метод map::lower_bound(r), и ползу от него вниз пока не найду нужный бокс.

fixed.

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

> map::lower_bound(r) ну это кагбы и есть дихотомия ;)

Есть ещё неплохая реализация kd-дерева в numerical recipes последнего (3-го) издания, там создают индексные массивы над вектором точек, накапливая результаты поиска в очереди по приоритетам ( ака {make,push,pop}_heap из STL), так что получается весьма быстро и незатратно по памяти.

Исходнечки (чесно стыренно в период их бесплатной раздачи с сайта авторов: http://ifile.it/oc8x4ae)

nikitos ★★★
()
Ответ на: комментарий от nikitos

Спасибо, но в этой задаче запросы идут кучно (в 99% случаев без смены бокса), так что тупое кэширование посл. результата дает невиданный прирост производительности;-)

C kd tree основная проблема - как его набить, если есть только набор готовых боксов. Я чуть попозжа потестирую сколько тратится именно на поиск бокса для реальных задач, если будет смысл - может и переползу.

AIv ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.