Способы хеширования числового вектора?

Существуют ли какие-либо известные хэш-алгоритмы, которые вводят вектор int и выводят один int, который работает аналогично скалярному произведению?

Другими словами, я думаю о хэш-алгоритме, который может выглядеть так в С++:

// For simplicity, I'm not worrying about overflow, and assuming |v| < 7.
int HashVector(const vector<int>& v) {
  const int N = kSomethingBig;
  const int w[] = {234, 739, 934, 23, 828, 194};  // Carefully chosen constants.
  int result = 0;
  for (int i = 0; i < v.size(); ++i) result = (result + w[i] * v[i]) % N;
  return result;
}

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

Алгоритм, который меня интересует, имеет целые векторы хеша, но что-то для float-векторов также было бы круто.

Разъяснение

Хэш предназначен для использования в хеш-таблице для быстрого поиска ключей/значений. Здесь нет проблем с безопасностью.

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

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

Ответы

Ответ 1

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

Простым экспериментом является хеширование английского словаря и сравнение того, сколько коллизий у вас есть на алгоритме A против алгоритма B.

Вы можете построить аналогичный эксперимент: произвольно генерировать $BIG_NUMBER возможных векторов длиной 7 или меньше. Хешируйте их по алгоритму A, хэш их по алгоритму B, затем сравните число и тяжесть столкновений.

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

Ответ 2

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

  • Ваши входы умножаются, поэтому увеличивается степень разделения между одинаковыми входными значениями на итерацию (например, 65 + 66 намного меньше 65 * 66), что хорошо.
  • Он детерминирован, если ваш вектор не должен считаться множеством, а не последовательностью. Для ясности, если v = {23, 30, 37} отличается от v = {30, 23, 37}?
  • Равномерность распределения будет варьироваться в зависимости от диапазона и хаоса входных значений в v. Однако это справедливо и для обобщенного целочисленного алгоритма хэширования.

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

Ответ 3

Python используется для хэш-кортежей таким образом (source):

class tuple:
    def __hash__(self):
        value = 0x345678
        for item in self:
            value = c_mul(1000003, value) ^ hash(item)
        value = value ^ len(self)
        if value == -1:
            value = -2
        return value

В вашем случае item всегда будет целым числом, которое использует этот алгоритм:

class int:
    def __hash__(self):
        value = self
        if value == -1:
            value == -2
        return value

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

Ответ 4

В то время как я, возможно, полностью недопонимаю вас, может быть, неплохо обработать вектор как поток байтов и немного знать хэш на нем, то есть SHA1 или MD5.

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