Die Herausforderung besteht darin, den schnellstmöglichen Code für die Berechnung des Hafnian einer Matrix zu schreiben .
Die Hafnian einer symmetrischen 2n
-by- 2n
Matrix A
ist definiert als:
Hier repräsentiert S 2n die Menge aller Permutationen der ganzen Zahlen von 1
bis 2n
, das heißt [1, 2n]
.
Der Wikipedia-Link gibt auch eine anders aussehende Formel an, die von Interesse sein kann (und es gibt noch schnellere Methoden, wenn Sie weiter im Web suchen). Die gleiche Wiki-Seite behandelt Adjazenzmatrizen, aber Ihr Code sollte auch für andere Matrizen funktionieren. Sie können davon ausgehen, dass alle Werte Ganzzahlen sind, aber nicht, dass sie alle positiv sind.
Es gibt auch einen schnelleren Algorithmus, der jedoch schwer zu verstehen ist. und Christian Sievers war der erste, der es umsetzte (in Haskell).
In dieser Frage sind die Matrizen alle quadratisch und symmetrisch mit einer gleichmäßigen Dimension.
Referenzimplementierung (beachten Sie, dass dies die langsamstmögliche Methode verwendet).
Hier ist ein Beispiel für Python-Code von 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
Die Aufgabe
Sie sollten Code schreiben, der, gegeben 2n
durch 2n
Matrix, sein Hafnian ausgibt.
Da ich Ihren Code testen muss, wäre es hilfreich, wenn Sie mir eine einfache Möglichkeit geben könnten, eine Matrix als Eingabe für Ihren Code zu verwenden, z. B. durch Einlesen des Standards. Ich werde Ihren Code in zufällig ausgewählten Matrizen mit Elementen testen ausgewählt aus {-1, 0, 1}. Der Zweck solcher Tests ist es, die Wahrscheinlichkeit zu verringern, dass der Hafnianer einen sehr großen Wert hat.
Idealerweise kann Ihr Code Matrizen genau so einlesen, wie ich sie in den Beispielen in dieser Frage angegeben habe. So würde die Eingabe [[1,-1],[-1,-1]]
beispielsweise aussehen . Wenn Sie ein anderes Eingabeformat verwenden möchten, fragen Sie bitte und ich werde mein Bestes tun, um dies zu berücksichtigen.
Partituren und Krawatten
Ich werde Ihren Code auf zufälligen Matrizen von zunehmender Größe testen und stoppen, wenn Ihr Code zum ersten Mal länger als 1 Minute auf meinem Computer dauert. Die Bewertungsmatrizen werden für alle Einreichungen konsistent sein, um die Fairness zu gewährleisten.
Wenn zwei Personen die gleiche Punktzahl erzielen, ist der Gewinner derjenige, der für diesen Wert von am schnellsten ist n
. Wenn diese innerhalb einer Sekunde voneinander entfernt sind, ist dies die zuerst veröffentlichte.
Sprachen und Bibliotheken
Sie können jede verfügbare Sprache und Bibliothek verwenden, die Sie möchten, aber keine bereits vorhandene Funktion, um das Hafnian zu berechnen. Wo immer möglich, wäre es gut, wenn Sie Ihren Code ausführen könnten. Fügen Sie daher bitte eine vollständige Erklärung dazu bei, wie Sie Ihren Code unter Linux ausführen / kompilieren, wenn dies überhaupt möglich ist. "
Mein Computer Die Timings werden auf meinem 64-Bit-Computer ausgeführt. Dies ist eine Ubuntu-Standardinstallation mit 8 GB RAM, AMD FX-8350 Eight-Core-Prozessor und Radeon HD 4250. Dies bedeutet auch, dass ich in der Lage sein muss, Ihren Code auszuführen.
Fordern Sie Antworten in mehr Sprachen
Es wäre toll, Antworten in Ihrer bevorzugten superschnellen Programmiersprache zu erhalten. So starten Sie die Dinge aus, wie etwa Fortran , nim und Rost ?
Bestenliste
- 52 Meilen mit C ++ . 30 Sekunden.
- 50 durch NGN Verwendung C . 50 Sekunden.
- 46 von Christian Sievers mit Haskell . 40 Sekunden.
- 40 Meilen mit Python 2 + Pypy . 41 Sekunden.
- 34 von ngn mit Python 3 + pypy . 29 Sekunden.
- 28 von Dennis mit Python 3 . 35 Sekunden. (Pypy ist langsamer)