Задача состоит в том, чтобы написать максимально быстрый код для вычисления матрицы Хафниана .
Hafnian симметричной 2n
матрицы с размерностью 2n
матрицы A
определяются следующим образом:
Здесь S 2n представляет множество всех перестановок целых чисел от 1
до 2n
, то есть [1, 2n]
.
Ссылка на википедию также дает другую формулу, которая может быть интересна (и даже более быстрые методы существуют, если вы загляните дальше в сеть). На той же вики-странице говорится о матрицах смежности, но ваш код должен работать и для других матриц. Можно предположить, что все значения будут целыми числами, но не все они будут положительными.
Существует также более быстрый алгоритм, но его трудно понять. и Кристиан Сиверс был первым, кто реализовал это (в Хаскеле).
В этом вопросе все матрицы квадратные и симметричные с четной размерностью.
Ссылочная реализация (обратите внимание, что это самый медленный из возможных методов).
Вот пример кода Python от мистера Xcoder.
from itertools import permutations
from math import factorial
def hafnian(matrix):
my_sum = 0
n = len(matrix) // 2
for sigma in permutations(range(n*2)):
prod = 1
for j in range(n):
prod *= matrix[sigma[2*j]][sigma[2*j+1]]
my_sum += prod
return my_sum / (factorial(n) * 2 ** n)
print(hafnian([[-1, 1, 1, -1, 0, 0, 1, -1], [1, 0, 1, 0, -1, 0, -1, -1], [1, 1, -1, 1, -1, -1, 0, -1], [-1, 0, 1, -1, -1, 1, -1, 0], [0, -1, -1, -1, -1, 0, 0, -1], [0, 0, -1, 1, 0, 0, 1, 1], [1, -1, 0, -1, 0, 1, 1, 0], [-1, -1, -1, 0, -1, 1, 0, 1]]))
4
M = [[1, 1, 0, 0, 0, 0, 0, 1, 0, 0], [1, 1, -1, 0, -1, 1, 1, 1, 0, -1], [0, -1, -1, -1, 0, -1, -1, 0, -1, 1], [0, 0, -1, 1, -1, 1, -1, 0, 1, -1], [0, -1, 0, -1, -1, -1, -1, 1, -1, 1], [0, 1, -1, 1, -1, 1, -1, -1, 1, -1], [0, 1, -1, -1, -1, -1, 1, 0, 0, 0], [1, 1, 0, 0, 1, -1, 0, 1, 1, -1], [0, 0, -1, 1, -1, 1, 0, 1, 1, 1], [0, -1, 1, -1, 1, -1, 0, -1, 1, 1]]
print(hafnian(M))
-13
M = [[-1, 0, -1, -1, 0, -1, 0, 1, -1, 0, 0, 0], [0, 0, 0, 0, 0, -1, 0, 1, -1, -1, -1, -1], [-1, 0, 0, 1, 0, 0, 0, 1, -1, 1, -1, 0], [-1, 0, 1, -1, 1, -1, -1, -1, 0, -1, -1, -1], [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, -1, 0], [-1, -1, 0, -1, 0, 0, 1, 1, 1, 1, 1, 0], [0, 0, 0, -1, 0, 1, 1, -1, -1, 0, 1, 0], [1, 1, 1, -1, 0, 1, -1, 1, -1, -1, -1, -1], [-1, -1, -1, 0, 0, 1, -1, -1, -1, 1, -1, 0], [0, -1, 1, -1, 1, 1, 0, -1, 1, -1, 1, 1], [0, -1, -1, -1, -1, 1, 1, -1, -1, 1, 0, -1], [0, -1, 0, -1, 0, 0, 0, -1, 0, 1, -1, 1]]
print(hafnian(M))
13
M = [[-1, 1, 0, 1, 0, -1, 0, 0, -1, 1, -1, 1, 0, -1], [1, -1, 1, -1, 1, 1, -1, 0, -1, 1, 1, 0, 0, -1], [0, 1, 1, 1, -1, 1, -1, -1, 0, 0, -1, 0, -1, -1], [1, -1, 1, -1, 1, 0, 1, 1, -1, -1, 0, 0, 1, 1], [0, 1, -1, 1, 0, 1, 0, 1, -1, -1, 1, 1, 0, -1], [-1, 1, 1, 0, 1, 1, -1, 0, 1, -1, -1, -1, 1, -1], [0, -1, -1, 1, 0, -1, -1, -1, 0, 1, -1, 0, 1, -1], [0, 0, -1, 1, 1, 0, -1, 0, 0, -1, 0, 0, 0, 1], [-1, -1, 0, -1, -1, 1, 0, 0, 1, 1, 0, 1, -1, 0], [1, 1, 0, -1, -1, -1, 1, -1, 1, 1, 1, 0, 1, 0], [-1, 1, -1, 0, 1, -1, -1, 0, 0, 1, -1, 0, -1, 0], [1, 0, 0, 0, 1, -1, 0, 0, 1, 0, 0, 1, 1, 1], [0, 0, -1, 1, 0, 1, 1, 0, -1, 1, -1, 1, 1, -1], [-1, -1, -1, 1, -1, -1, -1, 1, 0, 0, 0, 1, -1, -1]]
print(hafnian(M))
83
Задание
Вы должны написать код, который с 2n
помощью 2n
матрицы выводит свой гафнианский.
Поскольку мне нужно будет протестировать ваш код, было бы полезно, если бы вы могли дать мне простой способ дать матрицу в качестве входных данных для вашего кода, например, путем чтения из стандартного в. Я протестирую ваш код в случайно выбранных матрицах с элементами выбран из {-1, 0, 1}. Цель такого тестирования состоит в том, чтобы уменьшить вероятность того, что гафнян будет очень большой ценностью.
В идеале ваш код сможет читать в матрицах точно так же, как я это делал в примерах в этом вопросе, прямо из стандартного. Это означает, что ввод будет выглядеть, [[1,-1],[-1,-1]]
например. Если вы хотите использовать другой формат ввода, пожалуйста, спросите, и я сделаю все возможное, чтобы приспособиться.
Счета и связи
Я протестирую ваш код на случайных матрицах увеличивающегося размера и остановлюсь, когда ваш код займет больше 1 минуты на моем компьютере. Матрицы оценки будут согласованы для всех представленных документов, чтобы обеспечить справедливость.
Если два человека получают одинаковый результат, то победителем считается тот, кто быстрее всех получит это значение n
. Если они находятся в пределах 1 секунды друг от друга, то это тот, который размещен первым.
Языки и библиотеки
Вы можете использовать любой доступный язык и библиотеки, которые вам нравятся, но без ранее существовавшей функции для вычисления гафнианского. Там, где это возможно, было бы хорошо иметь возможность запускать ваш код, поэтому, пожалуйста, включите полное объяснение того, как запускать / компилировать ваш код в Linux, если это возможно.
Моя машина Время будет работать на моей 64-битной машине. Это стандартная установка Ubuntu с 8 ГБ ОЗУ, восьмиъядерным процессором AMD FX-8350 и Radeon HD 4250. Это также означает, что мне нужно иметь возможность запускать ваш код.
Звоните для ответов на нескольких языках
Было бы здорово получить ответы на своем любимом супер-быстром языке программирования. Для начала, как насчет Фортрана , Нима и Ржавчины ?
Leaderboard
- 52 миль с использованием C ++ . 30 секунд.
- 50 с использованием СПП C . 50 секунд
- 46 от Christian Sievers с использованием Haskell . 40 секунд
- 40 миль, используя Python 2 + pypy . 41 секунда
- 34 по ngn, используя Python 3 + pypy . 29 секунд
- 28 от Денниса с использованием Python 3 . 35 секунд (Pypy медленнее)