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

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

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

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

Ответы

Ответ 1

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

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

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

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

Ответ 2

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

ИЗМЕНИТЬ

Чтобы подгонять мое предположение, возьмите пример. Пусть, скажем, мы сохраняем 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] и т.д.). Но как мы теперь это делаем то же самое, например a[1][0]? Все местоположения рядом с ним в памяти теперь заняты вещами, расположенными рядом с a[0][0].

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

ИЗМЕНИТЬ

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

Ответ 3

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

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

Ответ 4

Это похоже на то, что может помочь R-tree. или один из его вариантов. В стандартной библиотеке С++ ничего подобного нет, но похоже, что в библиотеке кандидатов ускорения есть R-дерево Boost.Geometry (not часть повышения еще). Я бы посмотрел на это, прежде чем писать свои собственные.

Ответ 5

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

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

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

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

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

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

Ответ 9

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

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

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

r = (адрес/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-изображений, который использует вычисленное значение, называемое "stride", что в основном является индикатором того, что они перескакивают между адресами памяти и адресами массивов.

Ответ 10

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

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

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

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

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

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