La sfida è scrivere il codice più veloce possibile per calcolare l' hafniano di una matrice .
L'hafniano di una matrice simmetrica 2n
-by- è definito come:2n
A
Qui S 2n rappresenta l'insieme di tutte le permutazioni degli interi da 1
a 2n
, cioè [1, 2n]
.
Il link di Wikipedia fornisce anche una formula dall'aspetto diverso che potrebbe essere di interesse (e esistono metodi ancora più veloci se si guarda oltre sul web). La stessa pagina wiki parla delle matrici di adiacenza ma il tuo codice dovrebbe funzionare anche per altre matrici. Puoi presumere che i valori saranno tutti numeri interi ma non che siano tutti positivi.
C'è anche un algoritmo più veloce ma sembra difficile da capire. e Christian Sievers fu il primo ad implementarlo (in Haskell).
In questa domanda le matrici sono tutte quadrate e simmetriche con dimensioni pari.
Implementazione di riferimento (notare che sta usando il metodo più lento possibile).
Ecco alcuni esempi di codice Python di Mr. 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
L'obiettivo
Dovresti scrivere un codice che, dato 2n
da una 2n
matrice, genera il suo Hafnian.
Poiché avrò bisogno di testare il tuo codice, sarebbe utile se tu potessi darmi un modo semplice per dare una matrice come input al tuo codice, ad esempio leggendo dallo standard in. Proverò il tuo codice in matrici scelte casualmente con elementi selezionato da {-1, 0, 1}. Lo scopo di testare in questo modo è ridurre le possibilità che l'Hafnian abbia un valore molto grande.
Idealmente il tuo codice sarà in grado di leggere le matrici esattamente come le ho negli esempi in questa domanda direttamente dallo standard in. Questo è l'input che sembrerebbe [[1,-1],[-1,-1]]
per esempio. Se si desidera utilizzare un altro formato di input, si prega di chiedere e farò del mio meglio per accogliere.
Punteggi e pareggi
Metterò alla prova il tuo codice su matrici casuali di dimensioni crescenti e mi fermerò la prima volta che il tuo codice impiegherà più di 1 minuto sul mio computer. Le matrici di punteggio saranno coerenti per tutti gli invii al fine di garantire l'equità.
Se due persone ottengono lo stesso punteggio, il vincitore è quello che è il più veloce per quel valore di n
. Se quelli sono entro 1 secondo l'uno dall'altro, è quello pubblicato per primo.
Lingue e biblioteche
È possibile utilizzare qualsiasi lingua e libreria disponibili, ma nessuna funzione preesistente per calcolare l'hafniano. Laddove possibile, sarebbe bene poter eseguire il tuo codice, quindi per favore includi una spiegazione completa su come eseguire / compilare il tuo codice in Linux, se possibile ».
La mia macchina I tempi verranno eseguiti sulla mia macchina a 64 bit. Questa è un'installazione Ubuntu standard con 8 GB di RAM, processore AMD FX-8350 Eight-Core e Radeon HD 4250. Ciò significa anche che devo essere in grado di eseguire il codice.
Chiama per le risposte in più lingue
Sarebbe bello avere risposte nel tuo linguaggio di programmazione super veloce preferito. Per iniziare, che ne dici di fortran , nim e rust ?
Classifica
- 52 per miglia usando C ++ . 30 secondi.
- 50 da ngn utilizzando C . 50 secondi.
- 46 di Christian Sievers utilizzando Haskell . 40 secondi.
- 40 per miglia usando Python 2 + pypy . 41 secondi.
- 34 di ngn utilizzando Python 3 + pypy . 29 secondi.
- 28 di Dennis utilizzando Python 3 . 35 secondi. (Pypy è più lento)