Как найти ближайший вектор в {0,1,2} ^ 12, снова и снова - PullRequest
9 голосов
/ 19 ноября 2010

Я ищу пространство векторов длины 12 с записями 0, 1, 2. Например, один такой вектор -
001122001122. У меня около тысячи хороших векторов и около тысячи плохих векторов.Для каждого плохого вектора мне нужно найти ближайший хороший вектор.Расстояние между двумя векторами - это просто количество не совпадающих координат.Хорошие векторы не особенно хорошо организованы, и причина, по которой они «хороши», не кажется здесь полезной.Мой главный приоритет в том, чтобы алгоритм был быстрым.

Если я выполняю простой исчерпывающий поиск, мне нужно вычислить около 1000 * 1000 расстояний.Это кажется довольно тупым.

Если я сначала применю алгоритм Дейкстры с использованием хороших векторов, я могу рассчитать ближайший вектор и минимальное расстояние для каждого вектора в пространстве, так что каждый плохой вектор требует простого поиска.Но пространство содержит 3 ^ 12 = 531,441 векторов, поэтому предварительные вычисления - это полмиллиона вычислений на расстоянии.Не так много экономии.

Можете ли вы помочь мне придумать лучший способ?

Редактировать: Поскольку люди искренне спрашивают, что делает их "хорошими": каждый вектор представляет собой описание шестиугольной картины шестиравносторонние треугольники, которые являются 2D-изображением трехмерного расположения кубов (представим обобщенный Q-bert).Равносторонние треугольники - это половины граней кубов (45-45-90), наклоненные в перспективу.Шесть координат описывают природу треугольника (воспринимаемый пол, левая стена, правая стена), а шесть координат описывают природу краев (воспринимаемая непрерывность, два вида воспринимаемой несплошности).1000 хороших векторов - это те, которые представляют шестиугольники, которые можно увидеть, увидев кубы в перспективе.Причиной поиска является применение локальных поправок к шестнадцатеричной карте, полной треугольников ...

Ответы [ 5 ]

4 голосов
/ 19 ноября 2010

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

Код в Mathematica:

bad = Table[RandomInteger[5, 12], {1000}];
good = Table[RandomInteger[2, 12], {1000}];
distance[a_, b_] := Total[Sign@Abs[a - b]];

bestMatch = #[[2]] & /@ 
   Position[
    Table[Ordering@
      Table[distance[good[[j]], bad[[i]]], {j, Length@good}], {i, 
      Length@bad}], 1] // Timing

Как и следовало ожидать, Время следует закону O (n ^ 2):

alt text

1 голос
/ 19 ноября 2010

3 ^ 12 не очень большое пространство поиска. Если скорость важна, а универсальность алгоритма - нет, вы можете просто сопоставить каждый вектор с целым числом в диапазоне 0..531440 и использовать его в качестве индекса в предварительно вычисленной таблице «ближайших хороших векторов».

Если бы вы дали каждой записи в этой таблице 32-битное слово (чего более чем достаточно), вы бы искали для таблицы около 2 МБ в обмен на довольно мгновенный «расчет».

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

1 голос
/ 19 ноября 2010

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

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

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

Нет гарантий, что это правильно, так как и алгоритм, и код не в моей голове:

var goodTrie = new Trie(goodVectors)
var badTrie = new Trie(badVectors)
var result = new Map<Vector, Vector>()
var pq = new PriorityQueue(x => x.error)
pq.add(new {good: goodTrie, bad: badTrie, error: 0})
while pq.Count > 0
  var g,b,e = q.Dequeue()
  if b.Count == 0: 
      //all leafs of this path have been removed
      continue
  if b.IsLeaf:
      //we have found a mapping with minimum error for this bad item
      result[b.Item] = g.Item
      badTrie.remove(b) //prevent redundant results
  else:
      //We are zipping down the tries. Branch to all possibilities.
      q.EnqueueAll(from i in {0,1,2}
                   from j in {0,1,2}
                   select new {good: g[i], bad: b[j], error: e + i==j ? 0 : 1})

return result   

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

0 голосов
/ 19 ноября 2010

Предполагая упакованное представление для векторов, одно вычисление расстояния (сравнение одного хорошего вектора и одного плохого вектора для получения расстояния) может быть выполнено примерно за 20 тактовых циклов или меньше.Следовательно, миллион таких вычислений расстояния может быть выполнен за 20 миллионов циклов или (при условии, что процессор 2 ГГц) 0,01 сек.Помогают ли эти цифры?

PS: - 20 циклов - это консервативное завышение.

0 голосов
/ 19 ноября 2010

Моя вычислительная геометрия ОЧЕНЬ груба, но, похоже, вы должны быть в состоянии:

  1. Рассчитать диаграмму Вороного для вашего набора хороших векторов.
  2. Рассчитайте дерево BSP для ячеек диаграммы.

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

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

РЕДАКТИРОВАТЬ: Я только что заметилчто вы используете расстояния Хэмминга вместо евклидовых расстояний.Я не уверен, как это можно адаптировать, чтобы соответствовать этому ограничению.К сожалению.

...