【月刊組合せ論 Natori】ランダムヤングタブローと北極圏定理【2024 年 9 月号】
目次
月刊組合せ論 Natori は面白そうな組合せ論のトピックを紹介していく企画です。今回は $N\times N$ 型のヤングタブローにおいて $N\to\infty$ としたときにどうなるかを考えていきます。
ヤングタブロー #
$N\times N$ のマス目があります。ここに $1$ から $N^2$ までの整数を 1 つずつ、次の条件を満たすように書き込みます。
- 各行について単調増加
- 各列について単調増加
例えば $N=5$ のときは次のようになります。
このようなものをヤングタブローといいます。ヤングタブローの中から一様ランダムに 1 つ選んだとき、どのような形になるかを考えます。勿論このままではただの正方形なので、うまく可視化する必要があります。さらに $N\to\infty$ としたときどうなるかを考えます。このようなことを扱う分野を漸近的組合せ論 (asymptotic combinatorics) というそうです。
ヤングタブローの可視化 #
与えられたヤングタブローに対して $N$ 個のグラフを描きます。時刻 0 において $i$ 番目のグラフは高さ $N-i$ にあるものとします。
$k=1,2,\ldots,N^2$ の順に次の操作を行います。
- $k$ がタブローの $i$ 行目にあるとき、時刻 $k$ において $i$ 番目のグラフの高さを 1 増やす。
上のタブローでは次のようなグラフになります。
タブローの単調増加性より、どの 2 本も交わりません。
このグラフは Processing で描画しました。次のようなコードです。
size(500, 500);
background(255);
int[][] a = { { 1,2,4,6,10 },{ 3,5,9,13,14 },{ 7,8,12,18,20 },{ 11,16,19,22,23 },{ 15,17,21,24,25 }};
int n = a.length;
float dx = 480.0 / (n * n);
float dy = 480.0 / (2 * n - 1);
for (int i = 0; i < n; i++) {
float y = 10 + dy * n + dy * i;
float x = 10;
int j = 0;
for (int k = 1; k <= n * n; k++) {
line(x, y, x + dx, y);
x += dx;
if (j < n && a[i][j] == k) {
j++;
line(x, y, x, y - dy);
y -= dy;
}
}
}
それでは $N\to\infty$ としたとき、どのようなグラフになるかを調べていきましょう。
サンプリング #
ここで問題となるのが、ヤングタブローを一様ランダムに選ぶにはどうすればよいかということです。$N$ が大きくなるにつれ、ヤングタブローの個数は膨大になります。
そこで役立つのがフック長公式の証明です。確率を用いた証明ではフックウォークと呼ばれるものが用いられていますが、これが役に立ちます。過去に公開した記事をご覧ください。
【月刊組合せ論 Natori】フック長公式【2023 年 5 月号】
$\lambda$ 上のヤングタブローの個数を $F_{\lambda}$ とします。$\lambda$ から角 $c$ を除いた図形を $\mu$ とするとき、フックウォークの終点が $c$ となる確率が $\frac{F_{\mu}}{F_{\lambda}}$ となることを示していました。このことから、次のようなアルゴリズムによってヤングタブローを一様ランダムに選ぶことができます。
- 箱の総数が $n$ のヤング図形を考える。
- フックウォークを行い、終点に $n$ を書く。
- 残りの図形に再びフックウォークを行い、終点に $n-1$ を書く。
- これを繰り返す。
これを正方形ヤング図形の場合にコードにしたものが次のものになります。(本当はこれも Processing で書きたかったのですが、慣れていないので Kotlin で書きました)
fun main() {
val n = 10
val a = Array(n) { Array(n) { 0 } }
val cells = mutableSetOf<Pair<Int, Int>>()
for (i in 0 until n) {
for (j in 0 until n) {
cells.add(i to j)
}
}
for (num in n * n downTo 1) {
val firstCell = cells.random()
var x = firstCell.first
var y = firstCell.second
while (true) {
val candidates = mutableListOf<Pair<Int, Int>>()
for (i in x + 1 until n) {
if (a[i][y] == 0) {
candidates.add(i to y)
} else {
break
}
}
for (j in y + 1 until n) {
if (a[x][j] == 0) {
candidates.add(x to j)
} else {
break
}
}
if (candidates.isEmpty()) {
break
}
val choice = candidates.random()
x = choice.first
y = choice.second
}
a[x][y] = num
cells.remove(x to y)
}
print("{ ")
print(a.map { "{ ${it.joinToString(",")} }" }.joinToString(","))
println("};")
}
上の Processing のコードの a の定義を、このコードの出力で置き換えればよいです。
いざ実行 #
まずは $N=10$ で実行してみましょう。
なるほど。
次は $N=20$ で実行してみましょう。
おや?
次は $N=50$ で実行してみましょう。
おやおや?
何やら円が見えますね。円の内側で動いており、外側ではほとんど動かないようです。これが $N\to\infty$ としたときに見えてくる形です。このような現象は六角形のひし形タイル張りや、アステカダイヤモンドのドミノタイル張りなどでも現れ、arctic circle theorem と呼ばれています。直訳すると北極圏定理でしょうか。
おわりに #
組合せ論と確率論の関係というと、高校数学では当たり前という感じがしますが、大学数学では非自明で、奥深く、豊かな関係があります。この辺りももっと知りたいです。
参考文献 #
- Romik, Dan. Arctic circles, domino tilings and square Young tableaux. Ann. Probab. 40, No. 2, 611-647 (2012).
- Romik, Dan. The surprising mathematics of longest increasing subsequences. Cambridge University Press. (2015).