O desafio é escrever o código mais rápido possível para calcular o Hafnian de uma matriz .
O Hafnian de um simétrica 2n
-by- 2n
matriz A
é definida como:
Aqui S 2n representa o conjunto de todas as permutações dos números inteiros de 1
a 2n
, isto é [1, 2n]
.
O link da wikipedia também fornece uma fórmula de aparência diferente que pode ser interessante (e existem métodos ainda mais rápidos se você procurar mais na web). A mesma página da wiki fala sobre matrizes de adjacência, mas seu código também deve funcionar para outras matrizes. Você pode assumir que todos os valores serão inteiros, mas não que todos sejam positivos.
Também existe um algoritmo mais rápido, mas parece difícil de entender. e Christian Sievers foi o primeiro a implementá-lo (em Haskell).
Nesta questão, as matrizes são todas quadradas e simétricas, com dimensão uniforme.
Implementação de referência (observe que este está usando o método mais lento possível).
Aqui está um exemplo de código python do Sr. 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
A tarefa
Você deve escrever código que, dada uma 2n
por 2n
matriz, gera a Hafnian.
Como precisarei testar seu código, seria útil se você desse uma maneira simples de fornecer uma matriz como entrada para seu código, por exemplo, lendo a partir do padrão em. Testarei seu código em matrizes escolhidas aleatoriamente com elementos selecionado de {-1, 0, 1}. O objetivo de testes como esse é reduzir a chance de o Hafnian ser um valor muito grande.
Idealmente, seu código será capaz de ler as matrizes exatamente como as tenho nos exemplos desta pergunta, diretamente do padrão. Essa é a entrada que seria semelhante, [[1,-1],[-1,-1]]
por exemplo. Se você quiser usar outro formato de entrada, pergunte e farei o possível para acomodar.
Pontuações e laços
Testarei seu código em matrizes aleatórias de tamanho crescente e pararei na primeira vez em que o código demorar mais de 1 minuto no meu computador. As matrizes de pontuação serão consistentes para todos os envios, a fim de garantir justiça.
Se duas pessoas obtiverem a mesma pontuação, o vencedor será o mais rápido para esse valor de n
. Se estes estiverem a 1 segundo um do outro, será o primeiro publicado.
Línguas e bibliotecas
Você pode usar qualquer idioma e bibliotecas disponíveis que desejar, mas nenhuma função preexistente para calcular o Hafnian. Sempre que possível, seria bom poder executar seu código; portanto, inclua uma explicação completa de como executar / compilar seu código no Linux, se possível.
Minha máquina Os tempos serão executados na minha máquina de 64 bits. Esta é uma instalação padrão do ubuntu com 8GB de RAM, processador de oito núcleos AMD FX-8350 e Radeon HD 4250. Isso também significa que eu preciso executar seu código.
Solicite respostas em mais idiomas
Seria ótimo obter respostas em sua linguagem de programação super rápida favorita. Para começar, que tal fortran , nim e ferrugem ?
Entre os melhores
- 52 por milhas usando C ++ . 30 segundos.
- 50 por NGN usando C . 50 segundos.
- 46 por Christian Sievers usando Haskell . 40 segundos.
- 40 por milhas usando Python 2 + pypy . 41 segundos.
- 34 por ngn usando Python 3 + pypy . 29 segundos.
- 28 por Dennis usando Python 3 . 35 segundos. (Pypy é mais lento)