課題は、行列のハフニアンを計算するために可能な限り速いコードを書くことです。
対称のHafnian 2n
行列の2n
行列はA
次のように定義されます。
ここで、S 2nはから1
までの整数のすべての順列の集合2n
、つまりを表し[1, 2n]
ます。
ウィキペディアのリンクはまた、興味を引くかもしれない異なる見た目の数式を提供します(さらにWebを見ると、さらに高速な方法が存在します)。同じWikiページで隣接行列について説明していますが、コードは他の行列でも機能するはずです。値はすべて整数であると仮定できますが、すべてが正であるとは限りません。
より高速なアルゴリズム もありますが、理解するのは難しいようです。そして、Christian Sieversが(Haskellで)最初に実装しました。
この質問では、行列はすべて正方形で、偶数次元で対称です。
参照実装(これは可能な限り遅い方法を使用していることに注意してください)。
Xcoder氏のpythonコードの例を次に示します。
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
by 2n
マトリックスが与えられ、そのハフニアンを出力するコードを記述する必要があります。
コードをテストする必要があるので、たとえば標準入力から読み取ることによって、コードへの入力としてマトリックスを提供する簡単な方法を提供できると便利です。要素を持つランダムに選択されたマトリックスでコードをテストします{-1、0、1}から選択します。このようなテストの目的は、ハフニアンが非常に大きな値になる可能性を減らすことです。
理想的には、この質問の例にあるように、標準入力からまっすぐにコードをマトリックスで読み取ることができます。これは、[[1,-1],[-1,-1]]
たとえば入力は次のようになります。別の入力形式を使用する場合は、お問い合わせください。対応できるよう最善を尽くします。
スコアとタイ
サイズが増加するランダムマトリックスでコードをテストし、コンピューターでコードが1分以上かかったときに停止します。スコアリングマトリックスは、公平性を確保するために、すべての提出物で一貫しています。
2人が同じスコアを獲得した場合、勝者はその値に対して最も速いものですn
。それらが互いに1秒以内にある場合は、最初に投稿されたものです。
言語とライブラリ
使用可能な任意の言語とライブラリを使用できますが、ハフニアンを計算するための既存の関数は使用できません。可能であれば、コードを実行できるとよいので、可能な限りLinuxでコードを実行/コンパイルする方法の完全な説明を含めてください。
マイマシンタイミングは64ビットマシンで実行されます。これは、8GB RAM、AMD FX-8350 8コアプロセッサ、およびRadeon HD 4250を備えた標準のUbuntuインストールです。これは、コードを実行できる必要があることも意味します。
より多くの言語で回答を求める
お気に入りの超高速プログラミング言語で答えを得ることは素晴らしいことです。物事を始めるために、fortran、nim、rustはどうですか?
リーダーボード
- C ++を使用して52マイル。30秒。
- Cを使用したngnによる50。50秒。
- 46クリスチャンシーバーズによるHaskellの使用。40秒。
- Python 2 + pypyを使用して40マイル。41秒。
- 34 by ngn by Python 3 + pypy。29秒。
- Python 3を使用したDennisによる28。35秒。(Pypyは遅いです)