整数行列の行列式を求めるための素朴な方法としては有理数行列のLU分解が考えられるが、これは計算途中で分子分母が大きくなるため効率が悪い。
整数行列の行列式を求める効率的な方法として以下の2つが考えられる:
- 十分多くのpについてLU分解等でZ/pZ上の行列式を計算し、Chinese Remainder Theoremで復元する。
- 整数計算のみで掃き出しを行い、ちょうど割り切れることが保証されている除算によって計算を効率化する (Gauss-Bareiss)
ここでは後者を実装してみた。
例題は、0,1,-1からなる歪対称行列の行列式の平方根である。整数値歪対称行列の行列式の平方根は整数になり、Pfaffianと呼ばれる。Pfaffianは例えば平面グラフの完全マッチングの個数(FKT Algorithm)で使われる。mod nでの平方根は一意に決まらないから、mod nでの計算によってではこの値は求まらない。したがってこの問題は整数行列の行列式のよい例題となっている。
-
言語 : C++11
-
行列 : Eigen3
-
多倍長整数 : gmpxx
-
gb.cpp : Gauss-Bareissによる手法
-
lu.cpp : 素朴な方法(有理数でのLU分解?)
-
lu-double.cpp : 倍精度浮動小数点数での近似
実行方法 : 第1引数(任意)が行列の大きさ、第2引数(任意)が乱数のシード
n=50
- gb : 0.02s
- lu : 0.04s
n=100
- gb : 0.11s
- lu : 0.46s
n=150
- gb : 0.31s
- lu : 2.27s
n=200
- gb : 0.92s
- lu : 7.79s
n=250
- gb : 2.35s
- lu : 21.64s
n=300
- gb : 4.59s
- lu : 47.53s