エルミート標準形のアルゴリズム
エンタープライズソリューション事業ユニット (ESU) の石丸です。エクサウィザーズ Advent Calendar 2025 4日目の記事です。
はじめに
線形方程式系
整数係数の方程式の整数解を求める問題はディオファントス方程式と呼ばれ、実数の場合とは異なる困難があります。本記事では、線形ディオファントス方程式系
この記事は 2 年前に社内の勉強会で扱った内容を記事化したものです。アルゴリズムの実装に必要なことが不足なく全部書いてある資料が見つからなかったのがこれを書いた動機の一つですが、主要な部分については Eisenbrand (2010) と Micciancio (2014) の講義資料をベースにしています。証明は基本的に省略しているため、これらの資料を参照いただけると幸いです。
拡張ユークリッド互除法
まずは最も単純な 2 変数の例から始めましょう。
問題:
この問題については以下のことが知られています:
-
がc の倍数のとき、またその時に限って整数解が存在する\gcd(a, b) - 具体的な解は拡張ユークリッド互除法で高速に求まる
例 (Wikipediaより):
ユークリッドの互除法を適用すると
1071 = 1029 \cdot 1 + 42 1029 = 42 \cdot 24 + 21 42 = 21 \cdot 2 + 0
より、
から
このように 2 変数の場合は拡張ユークリッド互除法で高速に解けます。以降は一般の
実数の場合の復習
整数の場合を考える前に、まず実数の場合の解法を振り返ります。
この場合、
x_4 = 2 - 自由度があるので
としておくx_3 = \alpha x_2 = (4 - 3x_3 - 4 x_4) / 2 = -2 - (3/2)\alpha x_1 = -3 - x_2 + 2 x_4 = 3 + (3/2)\alpha
従って、
「階段型」には行階段形と列階段形があり、それぞれ次のような見た目の行列を指します。
特徴を言葉で説明すると、以下のようになります。
- 各行/各列の先頭の非ゼロ成分の位置が行階段形では右に、列階段形では下にずれていく。
- ゼロベクトルが後ろに固まっている。
実数行列は次の行基本変形/列基本変形を繰り返すことによって行階段形/列階段形に変形できるというのがガウスの消去法でした。
行基本変形は、以下の 3 つの操作です:
- 二つの行を入れ替える
- ある行に 0 でない定数を掛ける
- ある行の定数倍を他の行に加える
列基本変形は、以下の 3 つの操作です:
- 二つの列を入れ替える
- ある列に 0 でない定数を掛ける
- ある列の定数倍を他の列に加える
基本変形を使って
行基本変形による解法:
- 行基本変形で
を行階段形に変換する。つまり、ある正則行列A を左から掛けてP を行階段形にする。PA -
を解く。PAx = Pb が行階段形なので簡単。PA は正則なので、この方程式の解集合とP の解集合は同じ。Ax = b
列基本変形による解法:
- 列基本変形で
を列階段形に変換する。つまり、ある正則行列A を右から掛けてQ を列階段形にする。AQ -
とするとy = Q^{-1}x なので、Ax = AQQ^{-1}x = AQy を解く。AQy = b が列階段形なので簡単。AQ -
に基づいてx = Qy を復元する。x
整数の場合の困難
上の方法を整数の場合にも適用できるか考えてみます。
困難 1: 行階段形では解きにくい
行階段形の場合、実数なら簡単に解けますが、整数の場合はそうとは限りません。例えば以下の方程式系を考えます:
行基本変形を適用すると以下のようになります。
自由度があるので
一方、列階段形だったら解けそうです:
順に
困難 2: 列基本変形すると異なるディオファントス方程式になる
しかし、列基本変形にも問題があります。
例えば
つまり、列基本変形をするとディオファントス方程式として等価でなくなることがあるということです。線形代数的な考察のみで整数の場合を扱うのは難しいことがわかります。より端的に、次の例を考えます。
例: 二次元ベクトル
実数上であれば これは
格子
格子とは
定義: 行列
を
言い換えれば、列ベクトル
が格子です。

上の図は、ベクトル
格子の基底
定義: 格子
また、基底ベクトルを列ベクトルとする行列
注意として、格子の基底は一意ではないということがあります。例えば
です。下図は、同じ格子を生成する 2 つの異なる基底を示しています。

格子の determinant
定義:

上の図は、格子の基底が張る平行体(基本平行体)を示しています。この平行体の面積が格子の determinant です。
格子の determinant は、格子点の密度を表す量と解釈できます。determinant が大きいほど格子点がまばらで、小さいほど密になります。
ユニモジュラ操作と行列
行基本変形/列基本変形に代わる、格子を保つ操作を考えます。ベクトル
-
の整数倍を別のa_i に足すa_j にa_i を掛ける-1 -
を入れ替えるa_i, a_j
これらを任意に有限回繰り返す操作を ユニモジュラ操作 (unimodular operation) と呼びます。行列についても同じように列に対するユニモジュラ操作が定義されます。
定義: 整数正方行列で行列式が
ユニモジュラ行列とユニモジュラ操作については以下の性質が成り立ちます。
- ユニモジュラ操作/行列は、ユニモジュラ行列を右から掛けると(列に対する)ユニモジュラ操作になるという形で 1 対 1 対応する。
- 任意のユニモジュラ行列は単位行列に対するユニモジュラ操作で得られる。
- ユニモジュラ行列の逆行列はユニモジュラ行列。
仮にユニモジュラ行列
-
とするとy = U^{-1}x 。Ax = AUU^{-1}x = AUy を解く。AUy = b が列階段形なので簡単。AU -
に基づいてx = Uy を復元する。x
つまり、列に対するユニモジュラ操作で
エルミート標準形
定理: 任意の整数行列
-
は列階段形であるH - ピボットの存在する行の成分はピボット自身を含めて全て非負である
- ピボットとなる成分はその行の他の成分よりも真に大きい
例:
この行列では、2 行目の 8、4 行目の 3、5 行目の 4 がピボットです。
例:
このとき、格子の determinant は
以降、行フルランクな行列に絞って、エルミート標準形を求める素朴なアルゴリズムについて考えます。つまり、各行について以下を繰り返します:
- 互除法でピボットの右をすべてゼロにする
- ピボットの左からピボット列を引いてピボット以下にする
例としてある行列のある行
- 2 列目と 3 列目で互除法を行うと
が残る:\gcd(18, 12) = 6 \begin{bmatrix} 5 & 6 & 0 & 8 \end{bmatrix} - 2 列目と 4 列目で互除法を行うと、この行を
にできる\begin{bmatrix} 5 & 2 & 0 & 0 \end{bmatrix} - 1 列目から 2 列目の 2 倍を引いて、ピボット以下の値にするとこの行は
\begin{bmatrix} 1 & 2 & 0 & 0 \end{bmatrix}
疑似コードで表すと以下のようになります。
for i ← 1, ..., m
for j ← i + 1, ..., n
if A[i,j] ≠ 0
拡張ユークリッド互除法で A[i,i]x + A[i,j]y = gcd(A[i,i], A[i,j]) となる x, y を求める
列 i, j を [[x, -A[i,j]/gcd], [y, A[i,i]/gcd]] を右から掛けて変換
if A[i,i] < 0 なら列 i を -1 倍
for j ← 1, ..., i - 1
A[i,j] を A[i,i] で割った商と余りを q, r として列 j, i を [[1, 0], [-q, 1]] を右から掛けて変換
素朴なアルゴリズムの計算量を考えます。
-
回の算術演算とO(m^2n) 回の拡張ユークリッド互除法を要するO(mn) - ユニモジュラ行列
を陽に求めたい場合はU 回の算術演算が必要O(mn^2)
これを見ると多項式時間で解けそうに見えますが、計算中に現れる整数が指数的に大きくなることがあるため、多項式時間アルゴリズムではありません (Fang & Havas, 1997)。
最悪計算量が悪くても実践的には十分速いということはありえますが、実装してみるとランダム行列に対してもあまり速いとは言えないようでした。
行列によって計算時間のバラつきが大きいですが、絶対値 100 以下の
多項式時間アルゴリズム
多項式時間であること以外も考慮した理想的なアルゴリズムの性質としては以下がありそうです。ここではこれらを満たすアルゴリズムについて考えていきます。
- 計算中に登場する整数の大きさが入力の多項式サイズに抑えられる。
- 計算の途中で有理数型を必要としない。つまり、fraction-free なアルゴリズムである。
- 行フルランクとは限らない一般の行列に対してエルミート標準形を求められる。
- エルミート標準形に変換するためのユニモジュラ行列
も同時に求められる。U
計算に現れる整数の大きさを抑える
定理 (Schrijver, 1986):
例:
しかし、2 つ問題があります:
- 格子の determinant が事前にはわからない。
- エルミート標準形が求まれば determinant も求まるが…?
-
の代わりにA に対するユニモジュラ操作を行うため、[A|dI] を満たすユニモジュラ行列H = AU が同時に計算できない。U
1 については、以下の事実が使えます。
事実:格子にベクトルを追加すると、determinant は元の格子の determinant の約数になる。


上の図は、格子にベクトルを追加すると格子点が増えて determinant(基本平行体の面積)が小さくなることを示しています。つまり、
行列式はガウスの消去法で求まります。線形従属と分かった列を捨てながら消去法をして、線形独立なベクトルが
また、2 については次の問題が解ければよいです。
問題: エルミート標準形
-
の HNF がA であるH \Leftrightarrow の HNF が、ある行列A' := \begin{bmatrix}A \\ 0 \mid I_{n-m}\end{bmatrix} についてB であるH' := \begin{bmatrix}H \\ B \end{bmatrix} -
を満たすユニモジュラ行列A'U = H' はU も満たすAU = H -
は正則行列であるA'
したがって、
アルゴリズムのまとめ
これらをまとめると、エルミート標準形とユニモジュラ行列を求める fraction-free な多項式時間アルゴリズムは以下のように整理できます。わたしの実装例はこちらを参照してください。
-
から線形独立な行ベクトルを抜き出して、行フルランクなA 行列m' \times n を得るA' - Gram-Schmidt 直交化法で可能。fraction-free なアルゴリズムは Erlingsson, Kaltofen & Musser (1996) 参照。
-
のA' 本の線形独立な列ベクトルを任意に取って構成した正方行列の行列式m' を求めるd - ガウスの消去法で可能。fraction-free なアルゴリズムは Bareiss (1968) 参照。
-
の下部に単位ベクトルをA' 本追加してn - m' 正則行列n \times n を得る。A'' - 格子の determinant の倍数
を利用して、d のエルミート標準形A'' を多項式時間で求める。H'' の最初のH'' 行がm' のエルミート標準形A' である。H' - 最初に除いた線形従属な行は、Gram-Schmidt 直交化法の適用時にそれ以前の行の線形結合で表されているので、それに従って
からH' のエルミート標準形A を復元する。 (Micciancio, 2014)H -
を計算してU = H'' {A''}^{-1} のユニモジュラ行列A を得る。U - これも Bareiss (1968) で可能。
この流れをきちんと書いてくれている文献が見つからなかったのが記事を書いた動機の一つですが、よりスマートなやり方がある可能性はあります。
計算量解析
定理 (アダマール不等式): 実数行列
系:
系より、
以下、簡単のために
-
回の算術演算とO(n^3) 回の拡張ユークリッド互除法によってO(n^2) をエルミート標準形に変換できる。A - 計算中に現れる整数の大きさは高々格子の determinant の定数乗であり、
ビットで抑えられる。O(n\log(nB)) -
ビット整数の乗算は、素朴にはk 、Karatsuba 法でO(k^2) 、最速はO(k^{1.59}) で可能。O(k \log k) -
ビット整数の互除法はk 回の乗算で可能。O(k)
これらをまとめると、エルミート標準形は素朴な乗算で
実測
多項式時間アルゴリズムの実装でランダム行列に対してエルミート標準形とユニモジュラ行列を求めました。
- 絶対値 100 以下の
行列に対して 1.6 秒100 \times 100 - 絶対値
以下の10^9 行列に対して 7.2 秒100 \times 100 - 行フルランクとわかっている行列のエルミート標準形を求めるだけなら、絶対値
以下の10^9 行列で 2.9 秒100 \times 100
素朴なアルゴリズムと比較して、実測上も大幅に高速化されているようでした。
既存研究・実装
エルミート標準形のアルゴリズムの新しめの論文は例えば Birmpilis, Labahn & Storjohann (2022) で、イントロダクションからアルゴリズムの発展の歴史をたどることができます。少なくとも理論計算量についてはここで挙げたアルゴリズムより良いものが存在するようです。ただし、行列積が
応用上は疎行列の場合が気になりますが、研究は多くはないようです。疎行列の場合に
また、定番の高速な計算機代数ライブラリである PARI/GP にエルミート標準形を求める関数が実装されています。Python では cypari または cypari2 から使えます。cypari で絶対値
参考文献
- Bareiss, Erwin H. "Sylvester's identity and multistep integer-preserving Gaussian elimination." Mathematics of Computation 22 (1968): 565-578.
- Birmpilis, Stavros, George Labahn and Arne Storjohann. "A Cubic Algorithm for Computing the Hermite Normal Form of a Nonsingular Integer Matrix." ACM Transactions on Algorithms 19 (2022): 1-36.
- Cassels, John W.. “An introduction to the geometry of numbers (Reprint).” Classics in Mathematics (1997).
- Conforti, Michele, Gérard Cornuéjols and Giacomo Zambelli. "Integer Programming." (2014).
- Eisenbrand, Friedrich. “Integer Programming and Algorithmic Geometry of Numbers - A tutorial.” 50 Years of Integer Programming (2010).
- Erlingsson, Úlfar, Erich L. Kaltofen and David R. Musser. "Generic Gram-Schmidt orthogonalization by exact division." International Symposium on Symbolic and Algebraic Computation (1996).
- Fang, Xin Gui and George Havas. "On the worst-case complexity of integer Gaussian elimination." International Symposium on Symbolic and Algebraic Computation (1997).
- Giesbrecht, Mark. “Efficient parallel solution of sparse systems of linear diophantine equations.” International Workshop on Parallel Symbolic Computation (1997).
- Micciancio, Daniele and Bogdan Warinschi. “A linear space algorithm for computing the hermite normal form.” Electron. Colloquium Comput. Complex. TR00 (2001).
- Micciancio, Daniele. "Basic Algorithms." Lecture Notes on Lattice Algorithms and Applications (2014). https://cseweb.ucsd.edu/classes/sp14/cse206A-a/lec4.pdf.
- 講義ノート一覧は https://cseweb.ucsd.edu/classes/sp14/cse206A-a/ から辿れます。
- Schrijver, Alexander. "Theory of linear and integer programming." Wiley-Interscience series in discrete mathematics and optimization (1986).
-
より一般的な定義では、
の部分集合\mathbb R^n が格子であるとは「S が通常の加法に関してS の離散部分群であり、かつ\mathbb R^n であること」とされます。Wikipediaや Cassels (1997)はこの定義を採用しています。\mathrm{span}(S) = \mathbb R^n のような「格子」は\Lambda = \{\binom{1}{2}x : x \in \mathbb Z\} の格子ではないので注意。ただ、その場合でも\mathbb R^2 を\Lambda のある部分空間の格子と呼んで問題ないと思いますし、実際、文献によっては最初から\mathbb R^2 の任意の部分空間に対して格子を定義している例もありました。 ↩︎\mathbb R^n -
determinant は線形代数では行列式と訳されますが、格子の文脈でそう訳すと混乱を招きそうなので英語のまま使うことにしました。 ↩︎
-
末尾のゼロベクトルは無視します。エルミート標準形の「一意性」を成り立たせるためには、厳密には余分なゼロベクトルを無視する必要がありました。 ↩︎
Discussion