Способы хеширования числового вектора?
Существуют ли какие-либо известные хэш-алгоритмы, которые вводят вектор 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-ангориметр.