Пользовательский тест на равенство хеш-таблиц в Common Lisp - PullRequest
0 голосов
/ 22 мая 2018

Простой тест на равенство двух хеш-таблиц: (equalp ht1 ht2), который проверяет наличие (1) одинакового: аргумента теста, (2) одинакового количества хеш-таблиц, (3) одинаковых ключей и значений и (4)равные значения.Однако мне нужно более быстрое сравнение, поскольку этот простой тест потребляет около 40% времени выполнения программы (согласно статистическому профилированию в sbcl).Таким образом, похоже, что (1) и (4) и часть (3) не нужны.Ниже приведена попытка сократить время выполнения (включая предлагаемое улучшение по сравнению с coredump):

(defun hash-table-equal-keys (ht1 ht2)
  "Determines if all the keys of two hash tables are the same."
  (and (= (hash-table-count ht1) (hash-table-count ht2))
       (loop for key1 being the hash-keys of ht1
           always (gethash key1 ht2))))

Однако влияние на время выполнения незначительно.

Основное требование касается тольконаличие / отсутствие ключей в таблице, к которой интенсивно обращаются и обновляют во время выполнения.Ключи также вычисляются во время выполнения на основе некоторого числа переменных - например, sym1, sym2, ...--, значения которых взяты из фиксированного набора символов.В настоящее время я настраиваю это с помощью макроса, один аспект которого строит доступ / обновление хеш-таблицы с использованием (gethash (list sym1 sym2 ...) ht).Но для этого требуется неэффективная #'equal хеш-таблица, в дополнение к составлению и построению списка для ключа.

Более эффективный подход мог бы заключаться в том, что макрос создает доступ, такой как (gethash (intern (concatenate 'string (symbol-name sym1) (symbol-name sym2) ...)) ht), который в основном заменяет конкатенацию строк.для построения списка.Это также позволяет использовать хэш-таблицу #'eq.Есть ли какие-либо проблемы, связанные с этим подходом?

Обновление: изменение программы на использование хеш-таблицы # 'eq с объединением приводит к значительно худшей производительности.Очевидно, что перевод ключей из списков в символы требует слишком много накладных расходов.

Ответы [ 3 ]

0 голосов
/ 22 мая 2018

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

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

0 голосов
/ 23 мая 2018

Предыдущее уточнение заменено на более подробный ответ:

Как предлагалось ранее, сначала создайте хеш-таблицу, связывающую каждый возможный символ с целым числом (или фикснумом).Поскольку число символов меньше 100, их число может варьироваться от 1 до 99. Затем во время выполнения преобразуйте данную последовательность символов в соответствующие им целые числа: например, (sym1 sym2 sym3) -> (16 88 3).Их можно объединить в большее целое число, умножив первое на 1, второе на 100, а третье на 100x100 = 10000 и т. Д., Если будет больше целых чисел, суммируя по мере продвижения.Комбинация эффективна, поскольку основана на целочисленной арифметике.Полученное целое число должно быть уникальным для любой перестановки входных целых чисел и может использоваться в хэш-таблице eql для доступа к исходной последовательности символов.

0 голосов
/ 22 мая 2018

Первое условие теста (= (hash-table-count ht1) (hash-table-count ht2)) проходит как ht1, так и ht2.

...