Есть ли структура данных с такими характеристиками?

Я ищу структуру данных, которая позволила бы мне хранить M -by- N Двумерная матрица значений, непрерывно находящихся в памяти, так что расстояние в памяти между любыми двумя точками приблизительно равно евклидову расстоянию между этими точками в матрице. То есть, в типичном представлении основной строки в виде одномерного массива из M * N элементов, расстояние памяти различается между соседними ячейками в той же строке ( 1 ) и соседними ячейки в соседних строках ( N ).

Мне нужна структура данных, которая уменьшает или устраняет эту разницу. Действительно, названия такой структуры достаточно - я могу реализовать ее сам. Если ответы относятся к библиотекам для такого рода вещей, это тоже приемлемо, но их следует использовать с C ++.

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

13
задан Jon Purdy 23 August 2010 в 17:38
поделиться

10 ответов

Учитывая требование, что вы хотите хранить значения непрерывно в памяти, я настоятельно рекомендую вам изучить кривые заполнения пространства , особенно кривые Гильберта ].

Чтобы дать немного контекста, такие кривые иногда используются в индексах базы данных для улучшения локальности запросов многомерного диапазона (например, «найти все элементы с координатами x / y в этом прямоугольнике»), тем самым стремясь уменьшить количество различных страниц, к которым был осуществлен доступ. Немного похоже на R-деревья, которые уже предлагались здесь.

В любом случае, похоже, что вы привязаны к массиву значений M * N в памяти, поэтому, как я понимаю, весь вопрос заключается в том, как расположить значения в этом массиве. (Если я не неправильно понял вопрос.)

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

7
ответ дан 1 December 2019 в 20:56
поделиться

Ответ - нет. Подумайте об этом - память одномерна. Ваша матрица - двумерная. Вы хотите впихнуть это дополнительное измерение - без потерь? Этого не произойдет.

Что более важно, так это то, что как только вы удаляетесь на определенное расстояние, загрузка в кэш занимает одинаковое время. Если у вас есть промах в кэше, не имеет значения, находится ли он на расстоянии 100 или 100000. В принципе, вы не можете получить больше смежности/лучшую производительность, чем простой массив, если только вы не хотите получить LRU для вашего массива.

1
ответ дан 1 December 2019 в 20:56
поделиться

Похоже, что этому может помочь R-дерево. или один из его вариантов. Ничего подобного в стандартной библиотеке C ++ нет, но похоже, что есть R-дерево в библиотеке кандидатов на повышение Boost.Geometry (пока не является частью повышения). Я бы посмотрел на это, прежде чем писать свой собственный.

3
ответ дан 1 December 2019 в 20:56
поделиться

Вы можете посмотреть на кривые заполнения пространства, в частности на кривую Z-порядка, которая (в основном) сохраняет пространственную локальность.Однако поиск индексов может оказаться дорогостоящим в вычислительном отношении.

Если вы используете это, чтобы попытаться улучшить производительность кэша, вы можете попробовать метод, называемый «bricking», который немного похож на один или два уровня кривой заполнения пространства. По сути, вы подразделяете свою матрицу на плитки nxn (где nxn аккуратно помещается в кеш L1). Вы также можете сохранить плитки другого уровня, чтобы они поместились в кэш более высокого уровня. Преимущество этого метода перед кривой, заполняющей пространство, заключается в том, что индексы можно довольно быстро вычислить. Одна ссылка включена в статью здесь: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.30.8959

6
ответ дан 1 December 2019 в 20:56
поделиться

Невозможно «линеаризовать» двухмерную структуру в одномерную структуру и сохранить неизменным отношение близости в обоих направлениях. Это одно из фундаментальных топологических свойств мира.

Имея это, верно, что стандартный порядок хранения по строкам или столбцам, обычно используемый для представления 2D-массива, не лучший, когда вам нужно сохранить близость (насколько это возможно). Вы можете получить лучший результат, используя различные дискретные аппроксимации фрактальных кривых (кривые заполнения пространства).

Кривая Z-порядка является популярной для этого приложения: http://en.wikipedia.org/wiki/Z-order_ (curve)

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

3
ответ дан 1 December 2019 в 20:56
поделиться

Для этого вам необходимо повторно преобразовать адреса из пространства памяти в пространство исходного массива. Кроме того, вы подчеркнули только расстояние, которое все еще может вызвать некоторые проблемы (без направления)

Если у меня есть массив R x C и две ячейки в местоположениях [r, c] и [c, r], расстояние от некоторой произвольной точки, скажем [0,0], одинаково. И вы не сможете заставить один адрес памяти содержать две вещи, если только у вас нет одной из этих причудливых новых машин с кубитами.

Однако вы можете принять во внимание, что в основном массиве строк R x C каждая строка имеет длину C * sizeof (yourdata) байтов.И наоборот, вы можете сказать, что исходные координаты любого адреса памяти в пределах массива равны

r = (address / C) c = (адрес% C)

поэтому

r1 = (адрес1 / C)

r2 = (адрес2 / C)

c1 = (адрес1% C)

c2 = (адрес2% C) )

dx = r1 - r2

dy = c1 - c2

dist = sqrt (dx ^ 2 + dy ^ 2)

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

Чтобы найти здесь гораздо больше идей, поищите любой код обработки 2D-изображений, который использует вычисленное значение, называемое «шаг», которое, по сути, является индикатором того, что они прыгают. вперед и назад между адресами памяти и адресами массива

0
ответ дан 1 December 2019 в 20:56
поделиться

Вы можете представить свою 2D-матрицу как большую спираль, начинающуюся в центре и развивающуюся наружу. Размотайте спираль и сохраните данные в указанном порядке, а расстояние между адресами не менее приблизительно приближается к евклидову расстоянию между точками, которые они представляют. Хотя это не будет очень точно, я уверен, что вы тоже не сможете сделать что-то намного лучше. В то же время, я думаю, что даже в лучшем случае это окажет минимальную помощь вашему коду свертки.

1
ответ дан 1 December 2019 в 20:56
поделиться

Я думаю, вы забываете, что расстояние в памяти компьютера недоступно процессору компьютера, работающему пешком :), так что расстояние в значительной степени не имеет значения.

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

0
ответ дан 1 December 2019 в 20:56
поделиться

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

Один из способов добиться большей «близости» — разбить изображение на части. Если ваше ядро ​​свертки меньше размера плитки, вы обычно касаетесь не более 4 плиток в худшем случае. Вы можете рекурсивно размещать фрагменты в больших разделах, чтобы улучшить локализацию. Аргумент, подобный Стоксу (по крайней мере, я думаю, что это Стокс) (или некоторое вариационное исчисление) может показать, что для прямоугольников наилучшей формой (что означает рассмотрение произвольных подпрямоугольников) является меньший прямоугольник с тем же соотношением сторон.

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

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

Это также действительно стоит того для различных схем сжатия, таких как косинусные преобразования. (Вот почему, когда вы загружаете изображение, оно часто появляется в виде маленьких и меньших квадратов, пока не будет достигнуто окончательное разрешение.

В этой области есть много книг, и они полезны.

0
ответ дан 1 December 2019 в 20:56
поделиться

Я бы сказал "нет"! И если ответ оказывается «да», то он почти наверняка настолько нерегулярен, что будет намного медленнее для операции типа свертки.

РЕДАКТИРОВАТЬ

Чтобы уточнить мою догадку, возьмем пример. Допустим, сначала мы сохраняем a[0][0].Мы хотим, чтобы a[k][0] и a[0][k] были одинаковыми расстояниями и пропорциональны k, поэтому мы можем выбрать чередовать хранение первой строки и первого столбца (т.е. a[0][0], a[1][0], a[0][1], a[2][0], a[0] [2] и т. д.) Но как теперь сделать то же самое, например, для а[1][0]? Все места рядом с ним в памяти теперь заняты тем, что находится рядом с a[0][0].

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

РЕДАКТИРОВАТЬ

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

7
ответ дан 1 December 2019 в 20:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: