一つの例外を許す対称性
ドミノゲームから得た、任意グラフのゲーム値を決める一般定理
盤面をきれいな対称形にする必要は、どこまであるのだろう。隣接する頂点をペアにし、ペア群の結び方に対称性を残せば、一個の例外頂点をどこへつないでも、ゲームの値はペア数の偶奇だけで決まる。
本稿の主結果 T1 は、有限単純無向グラフ上の通常ルールの Arc Kayles に関する十分条件。証明手法の対称応手・mex帰納は既知であり、新技法の発明は主張しない。候補となる新規性は、任意接続の一例外を許す一般的な定式化にある。ただし、2×n の梯子に葉を一枚付けるという特殊例には、証明なしの既存記述がある(07節)。専門家査読と証明支援系による形式検証は未実施。
02〜05節で定理 T1 とその証明・応用・重み付き版を示す。06節では成立の境界を調べ、二例外では一律の保証が失われる一方、例外集合が三角形なら同じ型の式が成り立つことを示す。09節では証明の仕組みを取り出し、拡張に耐える局所条件(命題 M)と、自己同型を仮定しない等重量除去ゲーム(定理 R)を記録する。奇数クリーク一般への予想 K は K₅ の反例で撤回した。完成稿までの変更点は変更記録にまとめた。
ドミノを置くことを、辺を取ることへ
二人が交互に、まだ残っている隣接した二頂点を選び、その二頂点と、それらに接続する全ての辺を取り除く。合法手がなくなった側が負け。グラフが途中で分断されてもよく、孤立頂点は残っていても手には使えない。これが Arc Kayles の通常ルールである。格子のマスを頂点に見立てると、空いた隣接二マスにドミノを置く Cram と一致する。[1]
勝敗より少し詳しい量が Sprague–Grundy値 g(G) である。一手後の局面の値を全部集め、その集合に入っていない最小の非負整数を取る。
例えば mex ∅ = 0、mex {1,3} = 0、mex {0,2} = 1、mex {0,1} = 2。g = 0 は後手必勝、g ≠ 0 は先手必勝を表す。互いに接続しない複数のゲームを並べ、一手ごとに一つを選んで遊ぶ場合、その値は各値の XOR になる。これは既知の Sprague–Grundy 理論である。[1]
本稿で「値が変わらない」という意味
単独での勝敗だけでなく、別の独立なゲームとの和でも同じ働きをする。ただし、別のグラフへ頂点を共有してつなぐ部品置換まで保証するわけではない。この区別は反例付きで後述する。
隣接する対称ペアと、任意接続の一頂点
グラフ H の頂点を m 組のペア {aᵢ,bᵢ} に分ける。各ペアを同時に交換する写像を τ とする。ここでいう「対称性」は図形の左右対称ではなく、交換しても隣接関係が変わらないことである。交差した辺も、密につながったグラフも許す。
m ≥ 0 とする。有限単純無向グラフ G の頂点が、互いに素な m 組のペアと一頂点 z に分割されているとする。
- すべての i について aᵢbᵢ ∈ E(G)。すなわち、各ペアは一手で取れる。
- H = G − z 上で、τ(aᵢ) = bᵢ、τ(bᵢ) = aᵢ とする写像 τ が自己同型である。
z と H の間の辺は任意でよい。このとき、
したがって、m が偶数なら後手必勝、奇数なら先手必勝である。
条件2を完全に書けば、H の相異なる任意の頂点 x,y に対して、xy ∈ E(H) と τ(x)τ(y) ∈ E(H) が同値、という意味である。z を含む G 全体が対称である必要はない。また、ペアごとに独立して交換できるという強い仮定も置かない。必要なのは、全ペアを一斉に交換する一つの自己同型だけである。
連結性・平面性・二部グラフ性・次数上限は仮定しない。m = 0 では G は一頂点だけであり、式は g(G) = 0 を与える。
英語による正確な定式化
Let G be a finite simple undirected graph with vertex partition V(G) = {z} ⊔ ⨆ᵢ₌₁ᵐ {aᵢ,bᵢ}. Suppose every aᵢbᵢ is an edge, and the simultaneous interchange τ(aᵢ)=bᵢ, τ(bᵢ)=aᵢ is an automorphism of G−z. No restriction is imposed on the neighborhood of z. Under normal-play Arc Kayles, the Sprague–Grundy value of G is m mod 2.
The statement is proved below. Its exact general formulation was not located in the primary sources examined; the symmetry-response and mex-induction techniques are established methods.
例外のつなぎ方を変えても、値は変わらない
辺を選び、その両端の頂点を取り除くゲームです。最後に手を指せた側が勝ちます。対称な本体に加える頂点 z の接続を自由に変え、Grundy 値を確かめてください。
● 接続あり ○ 接続なし。本体の交換対称性を、z が壊しても構いません。
例外は 1 頂点。本体は定理の仮定を満たしています。
各 aᵢ と bᵢ を一斉に入れ替えても、本体の辺集合は変わりません。太い実線が各対の内部辺です。z が孤立していても構いません。
計算はこの端末だけで実行します。Grundy 値は、合法手の先の値から mex(含まれない最小の非負整数)を再帰的に求めます。有限個の実験による一致と、一般の盤面に対する証明は別の根拠です。
例外は消えるだけでなく、別の頂点へ移る
m に関する強い帰納法で証明する。m = 0 では辺がなく、g = 0。m > 0 とし、小さいペア数では定理が成立すると仮定する。p = m mod 2 と置き、すべての合法手を次の三種類に分ける。
辺 aᵢbᵢ を取る場合
そのペアが消え、m−1 ペアと同じ例外 z が残る。残ったペア群には τ の制限が自己同型として残るので、帰納仮定より次局面の値は (m−1) mod 2 = 1−p。よって p ではない。
辺 zaᵢ を取る場合
z と aᵢ が消え、相方 bᵢ が残る。bᵢ を新しい例外頂点と見なす。その他の m−1 ペアの誘導グラフは対称なままであり、新例外の接続は任意でよい。したがって次局面の値は再び 1−p。辺 zbᵢ の場合も同じである。
別々のペアに属する x,y の辺 xy を取る場合
一手後の局面を G′ とする。対称性により、鏡像の辺 τ(x)τ(y) が存在する。x と y は別々のペアに属するので、この鏡像の両端はまだ残っており、G′ から取れる合法手である。
さらにその辺を取った局面 G″ には、m−2 ペアと例外 z が残る。帰納仮定より g(G″) = (m−2) mod 2 = p。したがって G′ は、値 p の局面への合法手を持つ。mex の定義から、g(G′) ≠ pでなければならない。
g(G″) = p ⇒ g(G′) ≠ p
ここでは G′ 自体が定理の仮定を満たすとは言っていない。帰納仮定を使うのは二手後の G″ だけであり、途中の局面への不正な適用や循環論証はない。
p を排除し、必要なら 0 を用意する
以上で、G のどの一手後の局面も値 p を持たない。p = 0 なら、その集合の mex は 0 である。p = 1 なら m ≥ 1 なので、必須のペア内辺を一つ取れる。Case A により、その手は値 0 へ移る。従って 0 は一手後の値に現れ、1 は現れず、mex は 1 となる。どちらの場合も g(G) = p。証明終。
抽象化の要点
毎手後に全体の対称性が残るのではない。例外を使う手では「例外の役割を相方へ渡す」。対をまたぐ手では「二手後に同じ種類の局面へ戻す」。この二つで、任意の例外接続を許せる。
一マスの欠損は、場所を問わない
T1 の仮定を満たす対称なペア群 H に対し、次が従う。
| 操作 | 値 | 理由 |
|---|---|---|
| H をそのまま使う | m mod 2 | 孤立した例外 z を追加しても手は増えない。 |
| 任意の一頂点 v を取り除く(m ≥ 1) | (m−1) mod 2 | τ(v) が新しい例外となり、完全なペアが m−1 組残る。 |
| 一頂点 z を任意の相手へつなぐ | m mod 2 | T1 そのもの。N(z) を変えても値は不変。 |
応用1:2×n のドミノ盤
各列の上下二マスを一組にする。上下交換はグラフの自己同型で、各組は縦ドミノで取れる。従って一マスをどこに塞いでも、値は (n−1) mod 2。欠損の端・中央・上段・下段という違いは、この値には影響しない。欠損のない 2×n 盤の g = n mod 2 は既知の結果である。[2]ここで n ≥ 1 とする。
欠損ではなく、一頂点 z を一つの格子頂点だけにつなぐ(葉を一枚付ける)場合も T1 の特殊例であり、値は n mod 2 のまま変わらない。この特殊例には、証明なしの既存記述がある。[3]一マス欠けの盤面のうち、欠損が端の列にある場合は、2×(n−1) の梯子の角に葉を一枚付けた形そのものなので、この既存記述の範囲に含まれる。欠損が内側の列にある場合は、欠損が上段を左右に分け、残った相方が左右の格子をつなぐ唯一の頂点(切断点)になる。この形は、その記述に挙げられた追加の形には当たらない。内側の一マス欠けを扱う記述は、今回の照合範囲では見つからなかった(07節)。
応用2:任意のグラフを二層にする
任意の有限単純グラフ F を二つコピーし、対応する頂点同士を辺で結ぶ。これはデカルト積 F □ K₂ である。F が木でも、サイクルでも、密なグラフでも、値は |V(F)| mod 2。一頂点の欠損後は (|V(F)|−1) mod 2 になる。さらに、層交換と整合する交差辺を加えた場合も、T1 の条件を保つ限り同じ式が使える。
応用3:探索せずに選べる必勝手と応手
ペア分けが与えられている場合、m が奇数なら、最初にどのペア内辺を取っても m−1 が偶数の局面に移れる。偶数の局面を相手に渡した後は、次の応手を繰り返す。
| 相手の手 | こちらの応手 |
|---|---|
| 完全なペアを取った | 残った完全なペアを一組取る。 |
| 例外とペアの片側を取った | 相方を新例外にし、別の完全なペアを一組取る。 |
| 異なるペアをまたぐ辺を取った | その辺の鏡像の辺を取る。 |
相手が手を打てる偶数ペア局面では m ≥ 2 なので、上の応手は存在する。各往復で二ペア分が消え、同じ条件を満たす偶数局面へ戻る。グラフの全ゲーム木を読む必要はない。
これは、対分け・自己同型が与えられた場合の戦略である。任意の入力グラフから、そのような対分けを高速に発見できることまで証明したものではない。関連する例として、各辺とその像が頂点を共有しない対合による鏡像戦略については、その存在の判定がグラフ同型問題と同程度に難しいことが示されている。[4]また、先手必勝は完全なプレイを前提とする。どの手順でも総手数が同じ、という主張ではない。
頂点に複数の駒を置いても、同じ原理が使える
各頂点に非負整数個の駒を置く。一手で辺の両端から一個ずつ取り、片端の駒がゼロならその辺は使えない。ループは許さない。これは既知の Weighted Arc Kayles の一設定である。[5]
対称ペア {aᵢ,bᵢ} の両端に同数 cᵢ ≥ 0 の駒を置く。各ペア内辺を持ち、ペア群のグラフが全対交換で不変とする。任意接続の例外頂点 z にはちょうど一個の駒を置く。このとき、
例外頂点を置かない場合も同じ式が成立する。
証明。容量 c の頂点を、互いに隣接しない c 個の複製頂点へ展開する。元の各辺を、両側の複製頂点間の完全二部グラフに置き換える。各手は一組の複製を消し、元の容量を一ずつ減らす手に対応する。複製のどれを選ぶかによる重複は、mex の集合には影響しないので、展開前後のゲーム値は一致する。この重み展開は既知である。[5, §4 Corollary 2]
aᵢ と bᵢ の j 番目の複製をペアにすると、完全なペアは合計 Σcᵢ 組。ペア内辺があり、同時交換は、z の複製を除いた展開グラフの自己同型になる。z の複製は一個だけなので T1 を適用できる。容量0の頂点は初めから除いてよい。証明終。
同様に、例外のない対称な重み配置からどこか一頂点の駒を一個減らすと、残った相方の一複製が例外となり、値は (Σcᵢ−1) mod 2。一個増やすと増分の複製が例外となり、値は Σcᵢ mod 2 のままである。減らす場合には、その頂点の容量が正であることを前提とする。
二個の例外では、もう同じ結論にならない
中央の辺 ab を取ると孤立頂点二つだけが残り、値は0。端の辺を取ると一辺 K₂ が残り、値は1。したがって、
一ペアなら g = 1 という式が破れる。P₄ は非空のペア群と二例外を持つ、頂点数最小の連結反例である(4頂点・3辺)。非連結も許すなら、ペア内辺 ab と例外同士の辺 z₁z₂ だけからなる 2K₂ も反例になる。こちらは同じ4頂点で辺が2本しかなく、g(2K₂) = 1 ⊕ 1 = 0 ≠ 1 である。したがって P₄ を辺数まで含めた無条件の最小例とは呼ばない。
空のペア群を許すなら、二例外を一辺で結ぶ K₂ が2頂点の反例となる。二個の例外が常に失敗するという意味ではなく、任意接続についての一律保証が失われるという意味である。
重みの例外も「一個」が効く
三角形の容量を (1,1,2) とし、前二頂点をペア、容量2を例外にする。ペアを取れば値0、例外を使えば容量 (0,1,1) の一辺となり値1。よって元の値は2。W1 の例外容量を任意の正整数へ広げることはできない。
共有接点での部品置換はできない
z–a–b という3頂点の道は、値1の一例外局面。しかし z に新しい頂点 w をつなぐと P₄ になり値2。元の局面を「孤立した z と独立な一辺」に置き換えてから同じ接続をすると、独立な二辺になり値0。同じ値でも、接点を共有する外部文脈では振る舞いが変わる。
ほかの仮定を落とした場合
- ペア内辺がない:一ペアの二頂点を孤立させれば値0であり、m mod 2 = 1 と一致しない。
- ペア群の対称性がない:P₄ の頂点を道順に1,2,3,4とし、ペアを {1,2},{3,4} とする。ペア内辺はあるが、中間辺23の鏡像14がない。孤立例外を付けても g = 2 ≠ 0。
- ルールが違う:途中でグラフを分断してはいけないルールや、最後に取った側が負けるルールには、この証明をそのまま使えない。
一律の保証は消えても、族によっては残る
有限検査での観察:梯子への葉二枚の追加。2×n の梯子(F = Pₙ の二層グラフ)に、葉を一枚ずつ任意の二頂点へ付けた盤面を全列挙すると、n = 2〜8 では値が n mod 2 のままだった。一頂点に何枚も葉を付けた星(tuft)を二つ付けても、葉1〜3枚の組合せで n = 2〜6 では同じだった。葉二枚の検査範囲 n = 1〜8 で値が変わったのは、n = 1 の両端へ一枚ずつ付けた P₄ だけだった。三枚の葉では、検査した n = 2〜6 の各 n に値が変わる配置があった。これらは有限検査の観察であり、n ≥ 9 の二枚追加や n ≥ 7 の三枚追加についての一般的な証明は本稿では与えていない。梯子に限った二例外のこの振る舞いは、T1 の証明では扱えない。
一頂点 v に葉を何枚付けても、葉一枚の場合と同じ値になる。v を使う手はどの葉を選んでも v を消し、残りの葉を全て孤立させる。v を使わない手は葉の集まりをそのまま残す。この二点から、選択肢の値の集合が一致することを帰納法で確かめられる。
例外集合が三角形なら、一例外と同じ型の式が成り立つ
m ≥ 0 とする。G の頂点が、T1 の条件1・2を満たす m 組のペアと、三頂点集合 X に分割され、X が三角形 K₃ を誘導するとする。X と H = G − X の間の辺は任意でよい。このとき、
命題 K3 の証明:T1 へ一手で戻す
m に関する強い帰納法で示す。p = (m+1) mod 2 と置き、合法手を四種類に分ける。
ペア内辺 aᵢbᵢ。三角形を保ったまま m−1 ペアになり、帰納仮定より値は m mod 2 = 1−p。
X 内の辺。X の二頂点が消え、残る一頂点が任意接続の一例外になる。T1 より値は m mod 2 = 1−p。
X の頂点 x とペアの片側 aᵢ を結ぶ辺。一手後の局面には、X の残り二頂点を結ぶ辺が残る。その辺を取ると、bᵢ を例外とする m−1 ペアの T1 の局面になり、値は (m−1) mod 2 = p。したがって一手後の局面の値は p ではない。辺 xbᵢ も同じである。
ペアをまたぐ辺。T1 と同じく鏡像の辺で応じると、m−2 ペアと三角形 X の局面になり、帰納仮定より値は p。したがって一手後の値は p ではない。
以上で、どの選択肢も値 p を持たない。p = 1 のとき、X 内の辺を取る手が値0の選択肢を与えるので、mex は p となる。m = 0 では X 内の辺しか手がなく、値は1である。□
予想 K は反証済み:K₅ への拡張は成立しない
第6版で予想 K を撤回する。旧予想は「対称な m 組のペアに、任意接続の奇数クリーク K₂ₖ₊₁ を加えても g = (m+k) mod 2」というものだった。k = 0 の T1 と k = 1 の K3 は成立するが、k = 2 には反例がある。
11頂点の反例。本体は三つの独立な辺 {0,1}, {2,3}, {4,5}。X = {6,7,8,9,10} の間には K₅ の全10辺を置く。本体と X の接続は {0,6}, {0,9}, {2,7}, {4,8} の4辺だけとする。これでグラフ全体を指定した。本体は各ペアを交換しても不変なので、旧予想の仮定を満たす。
| 最初に取る辺 | 辺の数 | 一手後の値 |
|---|---|---|
| ペア内の辺、または K₅ 内の辺 | 3 + 10 | 全て0 |
| {0,6}, {0,9} | 2 | どちらも2 |
| {2,7}, {4,8} | 2 | どちらも1 |
表は17本の全合法手を尽くしている。一手後の値は、残存頂点を状態にする方法と、残存辺集合を状態にする方法で別々に mex 再帰を行い、全て一致した。再現コードと辺ごとの結果を下に収録する。
もう一つの反例:4本の長さ2のパスを K₅ に付ける
本体は {0,1}, {2,3}, {4,5}, {6,7}、クリークは {8,9,10,11,12}。追加する接続辺は {0,8}, {2,9}, {4,10}, {6,11} だけとする。これは K₅ の異なる4頂点に、長さ2のパスを一本ずつ付けたグラフである。
4本のペア内辺と10本のクリーク内辺の後は全て値1、4本の接続辺の後は全て値0。従って g = mex{0,1} = 2 で、旧予想の (4+2) mod 2 = 0 と異なる。こちらは勝敗も旧予想と異なる。
追加査読の画像はコード右側が切れていたため、m = 3 の例は上記の辺集合をこちらで具体化して確認したものであり、画像中コードの完全な転記ではない。m = 4 は画像の文章で特定できる構造を確認した。いずれの例にも最小性は主張しない。
反例の完全な再現コード(Python標準ライブラリのみ)
python odd_clique_counterexample_verify.py を実行すると、二つの反例の値と全ての一手後の値を検算し、同じ場所へJSONを保存する。
"""Refutations of conjecture K; normal-play Arc Kayles, standard library only.
Run: python odd_clique_counterexample_verify.py
Two independent state representations: remaining vertices and remaining edges.
"""
from functools import lru_cache
from itertools import combinations
from pathlib import Path
import json
def mex(values):
result = 0
while result in values:
result += 1
return result
def verify(m, attachments):
n = 2 * m + 5
pairs = [(2*i, 2*i+1) for i in range(m)]
clique = list(combinations(range(2*m, n), 2))
edges = tuple(sorted(pairs + clique + attachments))
assert len(set(edges)) == len(edges)
core = set(pairs)
tau = lambda v: v ^ 1
assert all(tuple(sorted((tau(a), tau(b)))) in core for a, b in core)
assert all(a < 2*m <= b < n for a, b in attachments)
moves = tuple((1 << a) | (1 << b) for a, b in edges)
@lru_cache(None)
def by_vertices(mask):
return mex({by_vertices(mask ^ move) for move in moves
if mask & move == move})
@lru_cache(None)
def by_edges(remaining):
# The state is an immutable edge set; isolated vertices have no moves.
options = set()
for a, b in remaining:
child = tuple((u, v) for u, v in remaining
if a not in (u, v) and b not in (u, v))
options.add(by_edges(child))
return mex(options)
full = (1 << n) - 1
first_moves = []
for edge, move in zip(edges, moves):
a, b = edge
child = tuple((u, v) for u, v in edges
if a not in (u, v) and b not in (u, v))
value = by_vertices(full ^ move)
assert value == by_edges(child)
kind = 'pair' if edge in pairs else 'clique' if edge in clique else 'attachment'
first_moves.append({'edge': list(edge), 'kind': kind, 'grundy': value})
vertex_value, edge_value = by_vertices(full), by_edges(edges)
predicted = (m + 2) % 2
assert vertex_value == edge_value != predicted
return {'m': m, 'k': 2, 'vertices': n, 'pairs': pairs,
'clique_vertices': list(range(2*m, n)), 'attachments': attachments,
'edges': edges, 'prediction_of_retracted_K': predicted,
'grundy_by_vertices': vertex_value, 'grundy_by_edges': edge_value,
'first_move_value_set': sorted({row['grundy'] for row in first_moves}),
'first_moves': first_moves}
if __name__ == '__main__':
examples = [verify(3, [(0, 6), (0, 9), (2, 7), (4, 8)]),
verify(4, [(0, 8), (2, 9), (4, 10), (6, 11)])]
report = {'status': 'conjecture_K_refuted', 'examples': examples,
'scope': 'two explicit counterexamples; no minimality claim'}
text = json.dumps(report, ensure_ascii=False, indent=2) + '\n'
Path(__file__).with_name('odd_clique_counterexample_results.json').write_text(text)
print(text, end='')
以前の実験との関係。第5版で K₅ の1,524例が式に一致したという実験記録は、その標本については正しい。しかし乱択した m = 3 の100例は今回の反例を捉えていなかった。有限個の一致は一般命題の証明ではなく、今回の一つの反例で旧予想の普遍的な主張は否定される。旧データは探索履歴として保持する。
三角形以外の三頂点の例外グラフ(P₃、K₂+K₁、3K₁)や、五頂点の C₅・K₅から一辺を除いたグラフ・蝶ネクタイ形では、m = 2 の乱択300例で値が一つに定まらなかった。少なくとも頂点数の奇偶だけでは、この違いを説明できない。K₃ ではクリーク構造が十分条件として働くことを証明したが、これらの対照実験はクリークであることの必要性を示すものではない。さらに、上の K₅ 反例により、奇数クリークであることだけでは旧予想の式を保証できないと分かった。
固定点がクリークをなす対合との関係
strictly matched involution は、固定点の集合がクリークをなし、固定されない各頂点がその像と隣接する対合である。[6][7]T1 は固定点が0個・1個の場合を、1個の固定点の接続を非対称にして拡げたものに当たる。固定点クリークの大きさ c を変えて、固定点の接続を対称に保ったまま乱択すると(c = 0〜3 は m = 0〜4、c = 4,5 は m = 0〜3、各 (c,m) で200例)、検査した c = 0, 1, 3, 5 の全標本で値が ⌊|V|/2⌋ mod 2 に一致し、c = 2, 4 には不一致の例があった。c = 3 は命題 K3 に含まれる。上の K₅ 反例は接続がペア交換に対して非対称であり、G 全体に対合を要求するこの狭いクラスの c = 5 については反例にならない。ここでの c = 5 の一致は引き続き有限検査の観察である。
c = 2 の最小規模の反例の一つは、ペア {a,b}、その両方に隣接する z₁、z₁ だけに隣接する z₂ からなる4頂点のグラフである。ab を取ると値1、z₁a または z₁b を取ると値0、z₁z₂ を取ると値1が残るので g = 2 となり、予測の0と食い違う。固定点の接続を対称にしても、固定点が二個なら破れる。このクラス上の Arc Kayles を扱った文献は、今回の照合では見つからなかった。
命題の新規性と、証明技法の新規性を分ける
2026 09 15に、Arc Kayles / Cram / Weighted Arc Kayles と、involution・automorphism・paired vertices・perfect matching・symmetry strategy・tufts・vertex deletion の組合せを検索し、次の一次資料の本文を照合した。第5版では、査読の指摘を受けて、Cram の数値データベース、strictly matched involution の周辺、対合を使う他のゲームも追加で照合した。
| 一次資料 | 確認した既知結果 | 今回の一般形との差 |
|---|---|---|
| Huggan–Stevens, 2016 [1] Theorem 1 | すべての極大マッチングが同じサイズであるグラフでは、そのサイズの偶奇がゲーム値を決める。 | T1 の族は、その仮定を満たすとは限らない。例えば2×3の梯子には、サイズ2と3の極大マッチングがある。 |
| Huggan–Tennenhouse, 2021 [2] Theorems 4.4–4.5 (arXiv 初版 [3] では 4.5–4.6) | 通常の2×n梯子の値と特定の突起付き盤面を扱う。4.5の証明に「応手で既知値へ戻り、途中の値を排除する」議論がある。梯子の値の定理の直後に、tuft(格子頂点を中心とするスター)を2個まで加えても値は変わらないという、証明なしの記述がある。 | 証明の中心的手法は既知として帰属。tuft 1個の場合は、T1 を梯子へ適用した特殊例に当たる(葉が複数なら、06節の「葉を何枚付けても一枚と同じ」を併用する)ので、この特殊例は既述として扱う。端の列の一マス欠けもこの形と一致する。tuft 2個の場合は T1 の範囲外であり、計算した範囲(葉一枚ずつなら n = 2〜8)では n ≥ 2 で正しかった(06節)。任意の隣接対付きグラフと任意接続の一例外をまとめた T1 と同じ一般記載は確認できなかった。 |
| Burke–Dailly–Oijid, v2 [4] Definition 5 / Theorem 6 | 全辺が自己同型による像の辺と頂点を共有しない場合、鏡像応手で後手必勝となる。 | T1 の τ はペア内辺を固定するため、その条件を満たさない。z の隣接は非対称でもよく、τ は G 全体の自己同型でなくてよい。 |
| Dailly–Gledel–Heinrich, 2018/2019 [5] §4, Corollary 2 | Weighted Arc Kayles と、重みを頂点の複製へ展開する同値性。 | 重み展開は既知。W1 はその既知同値と T1 を組み合わせた系として扱う。 |
| Andres et al., 2019 [7] §5.1, Theorem 7 / Corollary 8 | strictly matched involution を持つグラフを特徴づける。固定点がない場合は T1 の本体 H の構造に対応する。 | 本体のグラフ構造は既知。原典の対象は直交彩色ゲームであり、Arc Kaylesで任意接続の一例外を許す T1 の値の式は本文に見つからなかった。このクラス上の Arc Kayles そのものを扱った文献も、今回の検索では見つからなかった。 |
| Uiterwijk, 2018 [8] | 30マス未満の全ての盤面サイズについて Cram の終盤データベースを作り、空の盤面の値が既存文献と一致することを確認している。 | 要旨だけでは、一マス欠け局面の収録範囲や、その一般則の記載は確認できない。通常の空の 2×n 盤からは一手で二マスずつ埋まるため、一マスだけ欠けた局面には到達しない。データベースがそのような初期欠損も扱うかは、本文・データ仕様の照合が必要。 |
| Alvarado et al., 2021 [9] Theorem 6 | 平面グラフ上の別のゲーム(Game of Cycles)で、対合により各面が全体として不変か、その面のどの辺の像も同じ面に属さない、という仮定を置く。その下で、自分に移る辺がなければ後手必勝、端点が固定されない自己対合辺がちょうど1本なら先手必勝とする。 | 「一つだけの例外で勝者が反転する」という発想の近接例として帰属する。Arc Kayles の値の式ではない。 |
現時点での判定
T1:一般の場合の証明を本稿に記録。調査した一次資料で、同一の一般形は未確認。
既述の特殊例:2×n 梯子に葉を一枚付ける場合は、証明なしの記述が既にある。[3]端の列の一マス欠けはこの形と同じなので、欠損に関する候補は内側の列の場合に限る。
命題 K3:T1 から導いた結果として記録。同一の記載は今回の照合範囲で未確認。
旧予想 K:K₅ の具体的反例により反証済み・撤回。
証明技法:既知の対称応手と mex 帰納法の応用。新技法とは主張しない。
応用・系:T1 からの帰結。個々の盤面の結果が初出かどうかは別途確認が必要。
上表の既知結果の仮定へ直接当てはまらないことは、ほかの既知結果からも導けないことを意味しない。とくに Winning Ways 第3巻の関連箇所、接点付きグラフゲーム、line graph 上の Node Kayles、matching game という別名での結果には未照合部分がある。最優先の照合先は Winning Ways 第3巻の Cram の章である。梯子の値の出典であり、内側の一マス欠けの盤面を扱っている可能性が最も高い。今回も本文は取得できなかった。
また、[1][2][6][7]の全てに Melissa Huggan が共著者として入っている。T1 に近い結果が既にあるとすれば、この研究者の周辺が最も有力である。修士論文[10]は、今回もサイトの制限で本文を取得できなかった。検索結果に表示された目次には、道・スター・サイクル・車輪グラフ、Triple Packing、頂点の重み付けなどの章が並ぶ。本文の抜粋では、極大マッチングの偶奇が全て等しいグラフはサイズも全て等しい、という equimatchable 系の議論が中心だった。対称性を扱う章は目次に見当たらないが、全文照合ではないので未照合として扱う。
書籍原典や引用・被引用文献を網羅した優先権調査は完了していない。学術的新規性の確定や、未知の証明技法の発見とは表現しない。
tuft の記述の評価(第5版で修正)。第4版では、tuft 2個の記述を任意の葉追加へ読み替えると P₄ の反例に衝突し得る、と書いた。葉一枚ずつの全列挙範囲 n = 1〜8 では、衝突したのは n = 1 の P₄ だけであり、n = 2〜8 では記述どおりだった。有限検査から n ≥ 9 まで結論してはいない。本稿の証明はこの記述に依存しない。[2][3]
レビューを受けた追加照合:2-lift と既知の構造名
2026 09 15に、Arc Kayles / Cram と 2-lift・signed graph・double cover・fixed-point-free involution・Tweedledum–Tweedledee・matched involution の組合せも検索した。この追加範囲でも、任意接続の一例外まで含む T1 と同一の一般命題は未確認だった。
2-lift による正確な言い換え。H = G−z、M = {aᵢbᵢ : 1 ≤ i ≤ m} とする。各ペアを基底の一頂点と見れば、H から M の辺だけを除いたグラフは、次の対応で符号付き多重グラフの 2-lift として表せる。正の辺を同じ層へ、負の辺を交差させて持ち上げる構成は既知であり、この対応を T1 の本体へ適用したものが下表である。[11]
| 基底の辺 | 本体で対応する二辺 |
|---|---|
| 正の辺 i–j | aᵢaⱼ と bᵢbⱼ |
| 負の辺 i–j | aᵢbⱼ と bᵢaⱼ |
同じ二頂点間に正負の辺が両方あってよい。したがって基底を単純グラフに限定しない。H は、この 2-lift に各ペアを結ぶ完全マッチング M を加えたものである。この記述なら、ペア内辺をループで表す規約が不要になる。
レビューの「各頂点に負のループを置く」という表現は、規約を補えば使える。通常のループ(whole-loop)を交換置換で持ち上げるとペア間に平行二辺が生じる一方、half-loop の規約なら一本の辺に対応する。平行辺を単純化する場合には、単純化後を同じ意味での被覆とは呼べない。両者を区別する文献を確認した。[12]
本体の構造には既知の名前もある。H の交換自己同型は、strictly matched involution のうち固定点を持たない場合に該当する。参照論文は各非固定点とその像が隣接することを条件とし、固定点集合が空である場合も明示的に許している。ただし、そこで扱われるゲームは直交彩色ゲームである。この構造名の一致は、Arc Kayles の T1 が既知だという証拠とは分けて扱う。また、z を含む G 全体に同じ自己同型を要求してはいない。[6]
さらに、用語の導入元である2019年の著者公開原稿も確認した。§5.1 の Theorem 7 / Corollary 8 は、固定点クリーク C を許した形でグラフを特徴づけており、C が空の場合が H に対応する。C = {z} として全体の交換対称性を要求すると、z は各ペアの両端に同じように隣接しなければならない。T1 はその制限を課さない。この原稿中にも Arc Kayles の T1 や例外なしの値の公式は見つからなかった。なお、同論文には、strictly matched involution を持つグラフの同型類の個数の下界を弱める訂正記事が出ている。訂正の対象は §5.1 の特徴付けではない。[13]構造の既知性を明記した上で、任意一例外を許すゲーム値の命題を候補として残す。[7]
計算は証明の代わりにせず、反例検査に使う
主定理の根拠は上の一般証明である。追加で、定理式を解法に埋め込まず、各局面の全合法手を再帰的に探索する mex 計算と照合した。理論の独立監査と計算検査は、役割を分けたAIエージェントで実施した。
| 検査 | 範囲 | 検査数 | 不一致 |
|---|---|---|---|
| 主定理・全列挙 | m = 0,1,2,3。固定した対分けの下の全対称コアと、全 z 隣接 | 4,165 | 0 |
| 主定理・乱択 | m = 4,5,6,7 で各 2,000 / 1,000 / 300 / 30 回 | 3,330 | 0 |
| 重み付き・全列挙 | m = 1,2、各 cᵢ ∈ {1,2,3}、全対称コアと全 z 隣接 | 588 | 0 |
| 重み付き・乱択 | m = 3、各 cᵢ ∈ {1,2,3}、重複しない200設定 | 200 | 0 |
主定理の全列挙数は、m ペア間の二種類の辺軌道ごとに有無を選び、z の 2m 本の候補接続の有無を選んだ数 2m(m−1)+2m である。m = 0〜3 では 1+4+64+4096 = 4165。これは対分け・頂点ラベルを固定した設定数であり、非同型グラフ数ではない。乱択の seed は 20260915。主定理の乱択では重複設定が生じ得る。
重み付きの検査は、証明で用いた複製展開ではなく、残り容量のタプルを状態にした別の動的計画法で行った。検査対象の合計DP状態数は130,057。P₄ と容量 (1,1,2) の反例も直接計算で確認した。
主定理の再現コード(Python標準ライブラリのみ)
保存したファイルを python paired_core_verify.py で実行する。標準出力と同じ内容を実行場所の JSON ファイルへ書き出す。
from functools import lru_cache
from itertools import combinations
import random,json
def sg(n,edges):
moves=tuple((1<<u)|(1<<v) for u,v in edges)
@lru_cache(None)
def g(mask):
seen={g(mask^e) for e in moves if mask&e==e}
x=0
while x in seen:x+=1
return x
return g((1<<n)-1)
def core(m,bits):
edges=[(2*i,2*i+1) for i in range(m)]
k=0
for i,j in combinations(range(m),2):
for flip in (0,1):
if bits>>k&1:edges.extend([(2*i,2*j+flip),(2*i+1,2*j+1-flip)])
k+=1
return edges
report=[]
for m in range(4):
count=0
for bits in range(1<<(m*(m-1))):
e=core(m,bits)
for a in range(1<<(2*m)):
edges=e+[(2*m,j) for j in range(2*m) if a>>j&1]
value=sg(2*m+1,edges)
assert value==m%2,(m,bits,a,value)
count+=1
report.append({'pairs':m,'exhaustive_labeled_graphs':count})
rng=random.Random(20260915)
for m,counts in [(4,2000),(5,1000),(6,300),(7,30)]:
for _ in range(counts):
bits=rng.randrange(1<<(m*(m-1)));a=rng.randrange(1<<(2*m))
edges=core(m,bits)+[(2*m,j) for j in range(2*m) if a>>j&1]
assert sg(2*m+1,edges)==m%2
report.append({'pairs':m,'random_graphs':counts,'seed':20260915})
print(json.dumps(report,indent=2))
open('paired_core_results.json','w').write(json.dumps(report,indent=2))
重み付きの独立再現コード
python weighted_verify.py で実行する。
"""Independent WAK verification by direct capacity-state mex, without clone reduction.
Python standard library only. Run: python weighted_verify.py
"""
from functools import lru_cache
from itertools import product
from pathlib import Path
import json,random
def wak_grundy(capacities,edges):
edges=tuple(edges)
@lru_cache(None)
def dp(caps):
options=set()
for a,b in edges:
if caps[a] and caps[b]:
nxt=list(caps);nxt[a]-=1;nxt[b]-=1
options.add(dp(tuple(nxt)))
g=0
while g in options:g+=1
return g
return dp(tuple(capacities)),dp.cache_info().currsize
def core_edges(m,mask):
edges=[(2*i,2*i+1) for i in range(m)]
bit=0
for i in range(m):
for j in range(i+1,m):
for flip in range(2):
if mask>>bit&1:
edges.extend([(2*i,2*j+flip),(2*i+1,2*j+1-flip)])
bit+=1
return edges
def evaluate(m,c,coremask,adjmask):
z=2*m
capacities=[v for x in c for v in (x,x)]+[1]
edges=core_edges(m,coremask)+[(i,z) for i in range(z) if adjmask>>i&1]
got,states=wak_grundy(capacities,edges)
expected=sum(c)%2
return got,expected,states
def main():
report={'method':'capacity tuple dynamic programming with mex; no clone reduction used by verifier',
'seed':20260915,'exhaustive':[],'random':{},'counterexample':{},'total_checked':0,'violations':[]}
states=0
for m in (1,2):
checked=0;observed={}
for c in product(range(1,4),repeat=m):
for cm in range(1<<(m*(m-1))):
for am in range(1<<(2*m)):
got,expected,numstates=evaluate(m,c,cm,am)
states+=numstates;checked+=1
observed[got]=observed.get(got,0)+1
if got!=expected:report['violations'].append(dict(m=m,c=c,coremask=cm,adjmask=am,got=got,expected=expected))
report['exhaustive'].append(dict(pairs=m,capacities='each c_i in 1..3',symmetric_core_count=1<<(m*(m-1)),exception_neighbor_count=1<<(2*m),cases=checked,grundy_histogram=observed))
report['total_checked']+=checked
rng=random.Random(report['seed']);m=3;seen=set();observed={}
while len(seen)<200:
c=tuple(rng.randint(1,3) for _ in range(m));cm=rng.randrange(1<<(m*(m-1)));am=rng.randrange(1<<(2*m))
key=(c,cm,am)
if key in seen:continue
seen.add(key)
got,expected,numstates=evaluate(m,c,cm,am)
states+=numstates;observed[got]=observed.get(got,0)+1
if got!=expected:report['violations'].append(dict(m=m,c=c,coremask=cm,adjmask=am,got=got,expected=expected))
report['random']=dict(pairs=3,cases=200,capacities='each c_i in 1..3',sampling='uniform draws without duplicate parameter tuples',grundy_histogram=observed)
report['total_checked']+=200
g,n=wak_grundy([1,1,2],[(0,1),(0,2),(1,2)])
report['counterexample']=dict(graph='triangle',capacities=[1,1,2],core_pairs=[[0,1]],exception=2,actual_grundy=g,claimed_parity_if_generalized=1,option_grundy_values=[0,1])
report['sum_dp_states_across_cases']=states
dest=Path(__file__).with_name('weighted_verify.json')
dest.write_text(json.dumps(report,indent=2,ensure_ascii=False)+'\n')
print(json.dumps(report,indent=2,ensure_ascii=False))
assert not report['violations']
assert g==2
if __name__=='__main__':main()
今回の検査結果(二つの実行出力を統合)
これは一つのスクリプトの生出力ではない。main_theorem は主定理スクリプトの出力リスト、weighted_corollary は重み付きスクリプトの出力オブジェクトを、そのまま格納している。外側に記録種別と実験日を付けた。JSONの日付は機械処理向けに YYYY-MM-DD、本文の日付は「2026 09 15」の形で書く。
{
"record_type": "combined_script_outputs",
"date": "2026-09-15",
"main_theorem": [
{
"pairs": 0,
"exhaustive_labeled_graphs": 1
},
{
"pairs": 1,
"exhaustive_labeled_graphs": 4
},
{
"pairs": 2,
"exhaustive_labeled_graphs": 64
},
{
"pairs": 3,
"exhaustive_labeled_graphs": 4096
},
{
"pairs": 4,
"random_graphs": 2000,
"seed": 20260915
},
{
"pairs": 5,
"random_graphs": 1000,
"seed": 20260915
},
{
"pairs": 6,
"random_graphs": 300,
"seed": 20260915
},
{
"pairs": 7,
"random_graphs": 30,
"seed": 20260915
}
],
"weighted_corollary": {
"method": "capacity tuple dynamic programming with mex; no clone reduction used by verifier",
"seed": 20260915,
"exhaustive": [
{
"pairs": 1,
"capacities": "each c_i in 1..3",
"symmetric_core_count": 1,
"exception_neighbor_count": 4,
"cases": 12,
"grundy_histogram": {
"1": 8,
"0": 4
}
},
{
"pairs": 2,
"capacities": "each c_i in 1..3",
"symmetric_core_count": 4,
"exception_neighbor_count": 16,
"cases": 576,
"grundy_histogram": {
"0": 320,
"1": 256
}
}
],
"random": {
"pairs": 3,
"cases": 200,
"capacities": "each c_i in 1..3",
"sampling": "uniform draws without duplicate parameter tuples",
"grundy_histogram": {
"1": 102,
"0": 98
}
},
"counterexample": {
"graph": "triangle",
"capacities": [
1,
1,
2
],
"core_pairs": [
[
0,
1
]
],
"exception": 2,
"actual_grundy": 2,
"claimed_parity_if_generalized": 1,
"option_grundy_values": [
0,
1
]
},
"total_checked": 788,
"violations": [],
"sum_dp_states_across_cases": 130057
}
}第5版の追加検査:梯子の tuft と奇数クリークの例外
以下は以前の有限検査の記録である。第6版では別途構成した K₅ の反例2件を二つの状態表現で検算した。旧標本の一致を、予想 K の成立と解釈してはいけない。
| 検査 | 範囲 | 検査数 | 結果 |
|---|---|---|---|
| 梯子・葉一枚 | n = 1〜8、全ての付け位置 | 72 | 値の変化 0 |
| 梯子・葉一枚ずつ二か所 | n = 1〜8、同じ頂点を含む全ての位置の組 | 444 | 変化は n = 1 の 1 件(P₄)のみ |
| 梯子・tuft 二つ | n = 2〜6、各 tuft の葉1〜3枚、総頂点数18以下 | 1,800 | 値の変化 0 |
| 梯子・葉一枚ずつ三か所 | n = 2〜6、全ての位置の組 | 780 | 38 件で変化(各 n に存在) |
| 三角形の例外(命題 K3) | m = 0,1,2 は全対称コアと X の全接続を全列挙、m = 3 は乱択400 | 16,849 | 全て (m+1) mod 2 |
| K₅ の例外(撤回した予想 K の旧標本) | m = 1 は全列挙、m = 2・3 は乱択400・100 | 1,524 | この標本では全て一致。一般形は第6版の反例で否定 |
| 対照:他の例外グラフ | P₃、K₂+K₁、3K₁、C₅、K₅−e、蝶ネクタイ形、m = 2 で各300 | 1,800 | 全てで値が二種類以上 |
| 固定点クリーク付き対合 | c = 0〜3 は m = 0〜4、c = 4,5 は m = 0〜3。固定点の接続は対称、各 (c,m) で200 | 5,600 | c = 0,1,3,5 は ⌊|V|/2⌋ mod 2、c = 2,4 は不一致あり |
乱択seedは20260915。全列挙の件数は対分け・頂点ラベルを固定した設定数である。値は全て、式を使わない mex の全探索で求めた。
第5版の再現コード
python exception_family_verify.py で実行する。手元の環境では約10秒で終わる。結果はスクリプトと同じ場所に保存する。
"""Checks for the fifth edition: pendant tufts on 2xn ladders and odd-clique exception sets.
Python standard library only. Run: python exception_family_verify.py
Every value is computed by plain mex recursion over vertex subsets; no formula is built in.
"""
from functools import lru_cache
from itertools import combinations, combinations_with_replacement, product
from pathlib import Path
import json
import random
SEED = 20260915
def sg(n, edges):
moves = tuple({(1 << u) | (1 << v) for u, v in edges})
@lru_cache(None)
def g(mask):
seen = {g(mask ^ e) for e in moves if mask & e == e}
k = 0
while k in seen:
k += 1
return k
return g((1 << n) - 1)
def ladder(n):
"""2xn grid; column i is the pair (2i, 2i+1)."""
return ([(2 * i, 2 * i + 1) for i in range(n)]
+ [(2 * i, 2 * i + 2) for i in range(n - 1)]
+ [(2 * i + 1, 2 * i + 3) for i in range(n - 1)])
def core(m, bits):
"""Pairs (2i, 2i+1) with pair edges; each bit adds one swap-invariant orbit of two edges."""
edges = [(2 * i, 2 * i + 1) for i in range(m)]
k = 0
for i, j in combinations(range(m), 2):
for flip in (0, 1):
if bits >> k & 1:
edges += [(2 * i, 2 * j + flip), (2 * i + 1, 2 * j + 1 - flip)]
k += 1
return edges
def exception_set(m, x_edges, c, bits, adj):
"""m symmetric pairs plus an exception set X of c vertices (labels 2m..2m+c-1).
x_edges is the graph on X; adj chooses every X-to-pair edge independently (no symmetry)."""
edges = core(m, bits) + [(2 * m + a, 2 * m + b) for a, b in x_edges]
edges += [(2 * m + z, v) for z in range(c) for v in range(2 * m) if adj >> (z * 2 * m + v) & 1]
return sg(2 * m + c, edges)
def histogram(values):
out = {}
for v in values:
out[str(v)] = out.get(str(v), 0) + 1
return dict(sorted(out.items()))
def main():
rng = random.Random(SEED)
report = {'seed': SEED, 'ladder_tufts': {}, 'odd_clique_exceptions': {},
'controls': {}, 'strictly_matched_fixed_clique': {}, 'paw': {}}
# 1. Tufts on 2xn ladders. A tuft is a star whose centre is a grid vertex.
one, two, three, multi = [], [], [], []
for n in range(1, 9):
base = sg(2 * n, ladder(n))
assert base == n % 2
bad1 = sum(sg(2 * n + 1, ladder(n) + [(v, 2 * n)]) != base for v in range(2 * n))
pairs = list(combinations_with_replacement(range(2 * n), 2))
bad2 = [p for p in pairs
if sg(2 * n + 2, ladder(n) + [(p[0], 2 * n), (p[1], 2 * n + 1)]) != base]
one.append({'n': n, 'placements': 2 * n, 'changed': bad1})
two.append({'n': n, 'placements': len(pairs), 'changed': len(bad2), 'examples': bad2[:3]})
assert bad1 == 0
assert (len(bad2) == 0) == (n >= 2)
for n in range(2, 7):
base = n % 2
checked = bad = 0
for v, w in combinations_with_replacement(range(2 * n), 2):
for a, b in product(range(1, 4), repeat=2):
if 2 * n + a + b > 18:
continue
edges = ladder(n) + [(v, 2 * n + i) for i in range(a)] + [(w, 2 * n + a + j) for j in range(b)]
checked += 1
bad += sg(2 * n + a + b, edges) != base
multi.append({'n': n, 'leaf_counts': '1..3 per tuft', 'placements': checked, 'changed': bad})
assert bad == 0
triples = list(combinations_with_replacement(range(2 * n), 3))
bad3 = [t for t in triples
if sg(2 * n + 3, ladder(n) + [(x, 2 * n + i) for i, x in enumerate(t)]) != base]
three.append({'n': n, 'placements': len(triples), 'changed': len(bad3), 'examples': bad3[:3]})
assert bad3
report['ladder_tufts'] = {'one_leaf': one, 'two_single_leaves': two,
'two_tufts_multi_leaf': multi, 'three_single_leaves': three}
# 2. Exception set inducing K3 or K5, with arbitrary edges to the pairs.
K3 = list(combinations(range(3), 2))
K5 = list(combinations(range(5), 2))
k3 = []
for m in (0, 1, 2):
vals = [exception_set(m, K3, 3, bits, adj)
for bits in range(1 << (m * (m - 1))) for adj in range(1 << (6 * m))]
assert set(vals) == {(m + 1) % 2}
k3.append({'m': m, 'mode': 'exhaustive', 'cases': len(vals), 'values': histogram(vals)})
vals = [exception_set(3, K3, 3, rng.getrandbits(6), rng.getrandbits(18)) for _ in range(400)]
assert set(vals) == {0}
k3.append({'m': 3, 'mode': 'random', 'cases': 400, 'values': histogram(vals)})
k5 = []
vals = [exception_set(1, K5, 5, 0, adj) for adj in range(1 << 10)]
assert set(vals) == {1}
k5.append({'m': 1, 'mode': 'exhaustive', 'cases': len(vals), 'values': histogram(vals)})
for m, count in ((2, 400), (3, 100)):
vals = [exception_set(m, K5, 5, rng.getrandbits(m * (m - 1)), rng.getrandbits(10 * m))
for _ in range(count)]
assert set(vals) == {(m + 2) % 2}
k5.append({'m': m, 'mode': 'random', 'cases': count, 'values': histogram(vals)})
report['odd_clique_exceptions'] = {'K3_predicted': '(m+1) mod 2', 'K3': k3,
'K5_predicted': '(m+2) mod 2', 'K5': k5}
# 3. Other exception graphs on 3 or 5 vertices do not keep a single value.
controls = {'P3': (3, [(0, 1), (1, 2)]), 'K2+K1': (3, [(0, 1)]), '3K1': (3, []),
'C5': (5, [(i, (i + 1) % 5) for i in range(5)]),
'K5-e': (5, [e for e in K5 if e != (0, 1)]),
'bowtie': (5, [(0, 1), (0, 2), (1, 2), (2, 3), (2, 4), (3, 4)])}
for name, (c, xe) in controls.items():
vals = [exception_set(2, xe, c, rng.getrandbits(2), rng.getrandbits(4 * c)) for _ in range(300)]
controls_hist = histogram(vals)
assert len(controls_hist) > 1
report['controls'][name] = {'m': 2, 'cases': 300, 'values': controls_hist}
# 4. Strictly matched involutions: fixed-point clique C, every z in C symmetric to each pair.
for c in range(6):
rows = []
for m in range(0, 5 if c <= 3 else 4):
vals = []
for _ in range(200):
edges = core(m, rng.getrandbits(max(1, m * (m - 1))))
edges += [(2 * m + a, 2 * m + b) for a, b in combinations(range(c), 2)]
for z in range(c):
for i in range(m):
if rng.random() < .5:
edges += [(2 * m + z, 2 * i), (2 * m + z, 2 * i + 1)]
vals.append(sg(2 * m + c, edges))
rows.append({'m': m, 'cases': 200, 'values': histogram(vals),
'floor_half_order_mod2': (2 * m + c) // 2 % 2})
if c % 2 == 1 or c == 0:
assert set(vals) == {(2 * m + c) // 2 % 2}
report['strictly_matched_fixed_clique'][str(c)] = rows
# 5. Symmetric two-point clique already fails: the paw with a pendant at the triangle apex.
paw = [(0, 1), (2, 0), (2, 1), (2, 3)] # pair {0,1}; C = {2,3}
report['paw'] = {'edges': paw, 'pair': [0, 1], 'fixed_clique': [2, 3],
'grundy': sg(4, paw), 'floor_half_order_mod2': 0}
assert report['paw']['grundy'] == 2
dest = Path(__file__).with_name('exception_family_results.json')
dest.write_text(json.dumps(report, ensure_ascii=False, indent=2) + '\n')
print(json.dumps(report, ensure_ascii=False, indent=2))
if __name__ == '__main__':
main()
第5版の検査結果
{
"seed": 20260915,
"ladder_tufts": {
"one_leaf": [
{
"n": 1,
"placements": 2,
"changed": 0
},
{
"n": 2,
"placements": 4,
"changed": 0
},
{
"n": 3,
"placements": 6,
"changed": 0
},
{
"n": 4,
"placements": 8,
"changed": 0
},
{
"n": 5,
"placements": 10,
"changed": 0
},
{
"n": 6,
"placements": 12,
"changed": 0
},
{
"n": 7,
"placements": 14,
"changed": 0
},
{
"n": 8,
"placements": 16,
"changed": 0
}
],
"two_single_leaves": [
{
"n": 1,
"placements": 3,
"changed": 1,
"examples": [
[
0,
1
]
]
},
{
"n": 2,
"placements": 10,
"changed": 0,
"examples": []
},
{
"n": 3,
"placements": 21,
"changed": 0,
"examples": []
},
{
"n": 4,
"placements": 36,
"changed": 0,
"examples": []
},
{
"n": 5,
"placements": 55,
"changed": 0,
"examples": []
},
{
"n": 6,
"placements": 78,
"changed": 0,
"examples": []
},
{
"n": 7,
"placements": 105,
"changed": 0,
"examples": []
},
{
"n": 8,
"placements": 136,
"changed": 0,
"examples": []
}
],
"two_tufts_multi_leaf": [
{
"n": 2,
"leaf_counts": "1..3 per tuft",
"placements": 90,
"changed": 0
},
{
"n": 3,
"leaf_counts": "1..3 per tuft",
"placements": 189,
"changed": 0
},
{
"n": 4,
"leaf_counts": "1..3 per tuft",
"placements": 324,
"changed": 0
},
{
"n": 5,
"leaf_counts": "1..3 per tuft",
"placements": 495,
"changed": 0
},
{
"n": 6,
"leaf_counts": "1..3 per tuft",
"placements": 702,
"changed": 0
}
],
"three_single_leaves": [
{
"n": 2,
"placements": 20,
"changed": 4,
"examples": [
[
0,
1,
2
],
[
0,
1,
3
],
[
0,
2,
3
]
]
},
{
"n": 3,
"placements": 56,
"changed": 10,
"examples": [
[
0,
1,
2
],
[
0,
1,
3
],
[
0,
1,
4
]
]
},
{
"n": 4,
"placements": 120,
"changed": 8,
"examples": [
[
0,
1,
2
],
[
0,
1,
3
],
[
0,
1,
4
]
]
},
{
"n": 5,
"placements": 220,
"changed": 8,
"examples": [
[
0,
1,
2
],
[
0,
1,
3
],
[
0,
1,
4
]
]
},
{
"n": 6,
"placements": 364,
"changed": 8,
"examples": [
[
0,
1,
2
],
[
0,
1,
3
],
[
0,
1,
4
]
]
}
]
},
"odd_clique_exceptions": {
"K3_predicted": "(m+1) mod 2",
"K3": [
{
"m": 0,
"mode": "exhaustive",
"cases": 1,
"values": {
"1": 1
}
},
{
"m": 1,
"mode": "exhaustive",
"cases": 64,
"values": {
"0": 64
}
},
{
"m": 2,
"mode": "exhaustive",
"cases": 16384,
"values": {
"1": 16384
}
},
{
"m": 3,
"mode": "random",
"cases": 400,
"values": {
"0": 400
}
}
],
"K5_predicted": "(m+2) mod 2",
"K5": [
{
"m": 1,
"mode": "exhaustive",
"cases": 1024,
"values": {
"1": 1024
}
},
{
"m": 2,
"mode": "random",
"cases": 400,
"values": {
"0": 400
}
},
{
"m": 3,
"mode": "random",
"cases": 100,
"values": {
"1": 100
}
}
]
},
"controls": {
"P3": {
"m": 2,
"cases": 300,
"values": {
"1": 270,
"3": 30
}
},
"K2+K1": {
"m": 2,
"cases": 300,
"values": {
"1": 236,
"3": 64
}
},
"3K1": {
"m": 2,
"cases": 300,
"values": {
"0": 69,
"1": 126,
"3": 105
}
},
"C5": {
"m": 2,
"cases": 300,
"values": {
"0": 248,
"2": 52
}
},
"K5-e": {
"m": 2,
"cases": 300,
"values": {
"0": 283,
"2": 17
}
},
"bowtie": {
"m": 2,
"cases": 300,
"values": {
"0": 260,
"2": 40
}
}
},
"strictly_matched_fixed_clique": {
"0": [
{
"m": 0,
"cases": 200,
"values": {
"0": 200
},
"floor_half_order_mod2": 0
},
{
"m": 1,
"cases": 200,
"values": {
"1": 200
},
"floor_half_order_mod2": 1
},
{
"m": 2,
"cases": 200,
"values": {
"0": 200
},
"floor_half_order_mod2": 0
},
{
"m": 3,
"cases": 200,
"values": {
"1": 200
},
"floor_half_order_mod2": 1
},
{
"m": 4,
"cases": 200,
"values": {
"0": 200
},
"floor_half_order_mod2": 0
}
],
"1": [
{
"m": 0,
"cases": 200,
"values": {
"0": 200
},
"floor_half_order_mod2": 0
},
{
"m": 1,
"cases": 200,
"values": {
"1": 200
},
"floor_half_order_mod2": 1
},
{
"m": 2,
"cases": 200,
"values": {
"0": 200
},
"floor_half_order_mod2": 0
},
{
"m": 3,
"cases": 200,
"values": {
"1": 200
},
"floor_half_order_mod2": 1
},
{
"m": 4,
"cases": 200,
"values": {
"0": 200
},
"floor_half_order_mod2": 0
}
],
"2": [
{
"m": 0,
"cases": 200,
"values": {
"1": 200
},
"floor_half_order_mod2": 1
},
{
"m": 1,
"cases": 200,
"values": {
"0": 99,
"2": 101
},
"floor_half_order_mod2": 0
},
{
"m": 2,
"cases": 200,
"values": {
"1": 99,
"3": 101
},
"floor_half_order_mod2": 1
},
{
"m": 3,
"cases": 200,
"values": {
"0": 55,
"2": 145
},
"floor_half_order_mod2": 0
},
{
"m": 4,
"cases": 200,
"values": {
"1": 71,
"3": 129
},
"floor_half_order_mod2": 1
}
],
"3": [
{
"m": 0,
"cases": 200,
"values": {
"1": 200
},
"floor_half_order_mod2": 1
},
{
"m": 1,
"cases": 200,
"values": {
"0": 200
},
"floor_half_order_mod2": 0
},
{
"m": 2,
"cases": 200,
"values": {
"1": 200
},
"floor_half_order_mod2": 1
},
{
"m": 3,
"cases": 200,
"values": {
"0": 200
},
"floor_half_order_mod2": 0
},
{
"m": 4,
"cases": 200,
"values": {
"1": 200
},
"floor_half_order_mod2": 1
}
],
"4": [
{
"m": 0,
"cases": 200,
"values": {
"0": 200
},
"floor_half_order_mod2": 0
},
{
"m": 1,
"cases": 200,
"values": {
"1": 160,
"3": 40
},
"floor_half_order_mod2": 1
},
{
"m": 2,
"cases": 200,
"values": {
"0": 82,
"2": 118
},
"floor_half_order_mod2": 0
},
{
"m": 3,
"cases": 200,
"values": {
"0": 11,
"1": 100,
"3": 89
},
"floor_half_order_mod2": 1
}
],
"5": [
{
"m": 0,
"cases": 200,
"values": {
"0": 200
},
"floor_half_order_mod2": 0
},
{
"m": 1,
"cases": 200,
"values": {
"1": 200
},
"floor_half_order_mod2": 1
},
{
"m": 2,
"cases": 200,
"values": {
"0": 200
},
"floor_half_order_mod2": 0
},
{
"m": 3,
"cases": 200,
"values": {
"1": 200
},
"floor_half_order_mod2": 1
}
]
},
"paw": {
"edges": [
[
0,
1
],
[
2,
0
],
[
2,
1
],
[
2,
3
]
],
"pair": [
0,
1
],
"fixed_clique": [
2,
3
],
"grundy": 2,
"floor_half_order_mod2": 0
}
}
ここから先に残る問い
- 二例外の構造分類。任意接続は保証できないと分かった。一方で、梯子への葉二枚は検査した n = 2〜8 で値が保たれ、例外集合が三角形なら一般に式が成り立つ。どの接続なら値0/1にとどまり、どこで大きな値が現れるか。単なる十分条件から必要十分条件へ進める余地がある。
- 旧予想 K の撤回と成立範囲。奇数クリーク一般への式は K₅ の反例で否定された。本稿は T1・K3 の成立と、一般化が破れる具体例を記録するところで一区切りとする。追加の接続条件による分類は、本稿では扱わない。
- 任意一頂点追加に不変なグラフの逆問題。対称ペア条件は十分条件である。そのような対称性を持たなくても不変なグラフを含め、完全に特徴づけられるかは本稿では未解決。
- 接点を持つ部品の情報。通常のGrundy値だけでは共有接点での置換に足りない。どの追加情報を保持すれば、一例外構造を部品として組み合わせられるか。
これらは今後の探索問題であり、一般に未解決であると文献確認した主張ではない。新たな結果として進める前に、それぞれの先行研究照合が必要である。
盤面を外し、証明の仕組みを取り出す
一例外の定理で働いていたのは、形の対称性だけではなかった。扱いやすい局面から外れても、同じ値の別の局面へ一手で応じられることが、未知の選択肢を排除していた。ここでは拡張の許し方を定め、その範囲で値保存と同値になる局所条件を整理する。
ここでの「頂点」はゲームの局面、「辺」は一手の遷移を表す。前節までの盤面上の頂点とは区別する。対象は有限・非巡回で、双方の合法手が同じ、手がなくなった側が負けるゲームである。
| 段階 | 残す構造 | 結論 |
|---|---|---|
| T1 | 隣接ペアの交換対称性と一例外 | g = m mod 2 |
| 下の M | 指定値への手と、同じ値へ戻す応手 | 任意の非負整数ラベルを、未知部分の拡張から保護 |
| 下の R | 二ブロック内の補集合と、小さな例外集合 | 自己同型を仮定せず、等重量除去ゲームで g = m mod 2 |
命題 M:未知部分の拡張に耐える必要十分条件
有限有向非巡回グラフ D の局面集合を S ⊔ U に分ける。S は値を指定したい局面、U は値を指定しない局面である。空でない S に、候補ラベル c : S → {0,1,2,…} を与える。
許す拡張は、D を含む任意の有限有向非巡回グラフ D′ とする。ただし既存の辺を削除せず、S の全ての出辺は元のまま固定する。U と新しい局面からは、非巡回性を保つ範囲で自由に辺を追加できる。新しい局面から元の局面へ接続することも許す。
M の位置づけ。十分性は標準的な mex と応手の議論であり、必要性も私有のNimを自由に追加できることから短く導ける。M は、この拡張クラスに対する同値条件を整理した命題として扱う。とくに必要性は拡張クラスの選択に依存し、追加できるゲームや辺を制限した別のクラスで、そのまま必要条件になるとは限らない。役割は、T1 や R で使う証明の手順と、保証の範囲を明確にすることである。この位置づけに合わせ、第5版で呼称を「定理」から「命題」に改めた。
次の二つは同値である。
(保存)許される全ての D′ で、全ての s ∈ S に対して gD′(s) = c(s)。
(局所条件)全ての s ∈ S について、k = c(s) とすると次を満たす。
- 下位値の供給:各整数 0 ≤ j < k に対し、s → t、t ∈ S、c(t) = j となる直接の手がある。
- 同値の直接手を禁止:s → t かつ t ∈ S なら c(t) ≠ k。
- 未知側からの応手:s → u かつ u ∈ U なら、u → t、t ∈ S、c(t) = k となる既存の手がある。
三条件の確認に必要なのは、S の指定ラベルと、各 s から二手までの既存の接続である。U の Grundy 値そのものを計算する必要はない。ただし、S 全体でこれらの条件を満たすことが必要であり、たった一局面の周辺だけで他の指定ラベルも正しいと仮定してよいわけではない。
証明:十分性
任意の拡張 D′ を固定し、その非巡回性を使って後続局面から帰納する。s ∈ S、k = c(s) とする。条件1により、s の選択肢に値0,…,k−1が全てある。S 内の選択肢は条件2と帰納仮定により値 k ではない。
S 外の選択肢 u には、条件3により値 k の局面 t への手が残る。mex の定義から g(u) ≠ k。したがって s の全選択肢から値 k が除外され、下位値は全てそろうので g(s) = k。U の値の確定は不要である。□
証明:必要性と、小さいNimによる反証
全拡張で S の指定値が保存されると仮定する。*j は、値が j の通常のNimの山を表す。以下の追加ゲームは元の D に戻る手を持たない私有のコピーなので、必ず許される有限非巡回な拡張になる。
条件2。S 内の辺が同じ指定値 k を結ぶなら、保存された実際の Grundy 値も同じになってしまう。局面は自分と同じ値の選択肢を持てないので矛盾。
条件1。s から S 内の値 j < c(s) への手がないとする。全ての u ∈ U に、新たな選択肢 *j を一個ずつ追加する。これで全ての g(u) ≠ j。保存を仮定している S 内にも該当する後続値がないため、s は値 j の選択肢を一つも持たず、g(s) ≤ j < c(s) となり矛盾。
条件3。s → u、u ∈ U に対する同値への応手が欠けるとし、k = c(s) と置く。U のうち u 以外の各局面には *k を追加する。u には *0,…,*(k−1) を追加する(k = 0 なら追加なし)。u の U 内の後続は値 k ではなく、S 内の後続にも指定値 k はない。一方、u の下位値は全て補われるので g(u) = k。s が自分と同じ値の選択肢を持つことになり矛盾。
いずれも「全指定値が保存される」という仮定への矛盾である。作った拡張で壊れるのは少なくとも一つの指定値であり、選んだ s だけが必ず変わるとまでは主張しない。□
この拡張クラスでは、小さいNimだけで反証できる。
K = max{c(s) : s ∈ S} とすると、三条件のどれかが欠ける場合、元のゲームのまま、または大きさ K 以下のNimの山だけを追加した拡張で反証できる。これは、私有Nimの自由な追加を許すという設定の下で得られる、同値条件の一つの表現である。
T1 はこの命題のどこに入るか
T1 の仮定を満たす初期盤面から到達可能な全残存グラフを、局面グラフ D の頂点とする。そのうち、T1 の条件を満たす対分けと例外頂点の選び方が少なくとも一つ存在する局面 Q の集合を S とする。頂点数には、残った孤立頂点も含める。
ラベルは対分けに依存しない。どの T1 分解でもペア数は m = (|V(Q)|−1)/2 なので、対分けや例外頂点を選び直しても同じ c(Q) が得られる。この定義は頂点数だけを使っており、T1 のゲーム値の結論を先取りしていない。
ラベル1の局面には、ペア内辺を取ってラベル0の S 内局面へ進む手がある(条件1)。また、一手で頂点が二個減るため、S 内の一手では必ずラベルが反転する(条件2)。Case C の直後が、別の対分けによって S に入る場合も、この条件2で扱う。
一方、S の外へ出る手は、現在の局面で選んだ T1 分解について Case A・B ではあり得ず、Case C に限られる。その鏡像の辺を取れば、元の分解から二ペアを除いた S 内の後続局面へ進み、ラベルは元と同じになる(条件3)。その応手先も到達可能なので D 内にある。これで M の三条件がそろう。
したがって T1 の値を支えるのは、全ゲーム木の対称性ではなく、この証明書である。対称局面 S の出口と既存の応手を保つなら、S 外の局面に新しい有限ゲームへの手を追加しても S の値は変わらない。S 自体に自由に新しい手を追加してよい、という主張ではない。
定理 R:対称性を仮定しない等重量除去ゲーム
有限の資源集合 V の各要素 v に正の重み w(v) を与え、w(A) = Σv∈Aw(v) とする。合法手はあらかじめ指定した集合族 ℋ で、全ての e ∈ ℋ が同じ合計重量 W > 0 を持つ。一手で残っている e の全要素を取り除く。除去後は、残存集合に完全に含まれる元の合法手だけを使う。
V = E ⊔ B1 ⊔ ⋯ ⊔ Bm と分割でき、次を満たすとする。
- 各本体ブロック Bi は合法手。
- 例外集合の重量は ρ = w(E) < W。
- E に触れない合法手は一つの本体全体か、二本体 Bi ∪ Bj の中にある。後者で両本体にまたがる手 e には、補集合 (Bi ∪ Bj) ∖ e も合法手として存在する。
- E に触れる合法手は、E と一つだけの本体を合わせた E ∪ Bi の中にある。
取り除く個数も、本体ブロックの個数以外の形も、頂点の交換自己同型も仮定しない。ただし「重量が等しい」ことだけで合法手が決まるのではない。ℋ は指定済みであり、特に補集合の合法性は別条件である。
自己同型が不要になるのは、どの範囲か。重みが全て1で W = 2 の場合、本体は二頂点のペア、例外は高々一頂点である。二つのペアにまたがる辺 xy の補集合は、x と y それぞれの相方を結ぶ辺であり、T1 の交換 τ による像そのものになる。したがってこの場合の条件3は T1 の交換自己同型の条件と同じで、例外なしの場合も含めて R と T1 は同じ内容になる。R で E = ∅ の場合は、孤立した例外頂点を追加して T1 を適用すればよい。自己同型を仮定しないことが実際に効くのは、重みが全て1で W = r ≥ 3 の場合か、重みが一様でない場合である。下の非対称な例は r = 3 である。
R の証明:例外集合の移送を含む閉包確認
m = 0 では総重量が W 未満なので手がない。p = m mod 2 とし、m に関する強い帰納法を用いる。
本体 Bi を取れば、条件を保って m−1 本体になる。例外に触れる手 e ⊆ E ∪ Bi では、残り E′ = (E ∪ Bi) ∖ e を新しい例外集合とする。重量は w(E′) = ρ + W − W = ρ であり、m−1 本体が残る。
ここで条件が保たれることを確かめる。旧 E ∪ Bi 内の手は残れない。残るなら E′ 内に重量 W の集合があることになり、ρ < W に反する。旧 E ∪ Bj または旧 Bi ∪ Bj にあった残存手は、新しい E′ ∪ Bj に収まる。それらが E′ に触れなければ、正の重みと重量 W から Bj 全体に等しい。i を含まない二本体内の手は、その補集合とともに丸ごと残る。各未除去本体も残る。よって新しい分割でも全条件が成立し、以上二種類の手の直後の値は 1−p。
二本体にまたがる手 e の後には、互いに素な合法補集合が残る。その応手で二本体を取り切れば、m−2 本体の同族で値 p。従って e の直後の局面は値 p を持てない。全ての選択肢が p と異なり、p = 1 のときは本体を取る値0の選択肢があるので、mex は p となる。□
二個取る手と三個取る手が、同じゲームで共存する
W = 4 とし、合法手を次の七つだけにする。
例えば ac と bde は二本体の中の互いに補集合であり、どちらも重量4。例外を使う三手は、それぞれ一つの本体と z の中に収まる。本体は二個なので g = 0。二個除去と三個除去の混在は、元の単純グラフ上の Arc Kayles の直接の範囲を越えている。
本体自体が非対称な例もある
各資源の重量を1、W = 3 とし、本体を 012、345、678 とする。数字列はその数字の頂点集合を表す。追加の合法手を、補集合の四対 015 / 234、025 / 134、027 / 168、356 / 478 とする。全11手で g = 1 となる。
このハイパーグラフは恒等写像以外の自己同型を持たない。以下で確認できる。次数は0〜5が4、6〜8が3。各頂点に接続する超辺について、他の二頂点の次数の組を多重集合として集めると、自己同型で保たれる四群 X = {0,2,3,5}、Y = {1,4}、Z = {6,7}、{8} に分かれる。
X のうち、Y の二頂点と同じ超辺に入るのは3だけなので3が固定される。残る X の頂点0,2,5が3と共有する超辺数は順に0,1,2であり、全て固定される。Y の1,4では1,3、Z の6,7では1,0と区別できる。8はもともと単独群である。よって全頂点が固定される。局所的な補集合条件は、全体の対称性を要求していない。
どこまで一般化できたか
全資源の重みを1、W = r とすれば「毎手 r 個を取る」ゲームになる。例外は q < r 個まで許され、r = 2、q = 1 が T1 を含む。r ≥ 3 では、例外に触れる手が二本体以上へまたがらないという制約が効く。例外が r−1 個までなら接続は何でもよい、とは言っていない。
この局所性を落とす反例は小さい。三個ブロック A = {a,b,c}、B = {d,e,f} と例外 z に対し、合法手を A、B、{z,a,d} だけにする。最後の手は二本体を同時に壊して終局となり、値0へ移る。本体を取れば値1へ移る。従って g = mex{0,1} = 2 となり、本体二個の偶奇0と食い違う。
既知理論との境界と、検証
値の異なる選択肢と同値への応手は、既知の mex・可逆応手・semi-kernel に近い。各 k ∈ c(S) について Sk = {s ∈ S : c(s) = k} とすると、M の条件2・3は「Sk が誘導有向グラフ D[U ∪ Sk] の semi-kernel」という既知概念で表せる。下位全値を供給する条件1を別に加えている。semi-Grundy 関数も近接概念であり、新しい証明技法としては扱わない。[14]また M の十分性には、同じ値へ戻る応手で余分な選択肢を扱うという、可逆な選択肢(reversible option)の標準理論に通じる構造がある。ただし、M の拡張クラスとの同値性まで同書に記載されているとは主張しない。[15]
集合を取るゲームモデルも既知で、ハイパーグラフ版 Arc Kayles や、各山の大きさを0/1とした hypergraph Nim の枠組みに入る。[16][17]今回調べた一次資料では、M の任意拡張との同値な定式化と、R の等重量・局所補集合・例外移送を組み合わせた一般形の同一記載は未確認である。ただし、M の同じ記載が見つからないことを、新しい一般理論や新技法を得たという評価にはつなげない。新規性の追加調査は、主に T1 や R の具体的な構造条件と適用範囲に向ける。検索語は semi-kernel / semi-Grundy / partial Grundy / extension / robustness、および hypergraph Arc Kayles / complementary / pairing strategy / normal play など。関連する Huggan の2015年修士論文は本文を取得できず(07節)、網羅的な新規性確認ではない。[10]
| 今回の検査 | 実施した範囲 | 結果 |
|---|---|---|
| M:全小DAGと指定ラベル | 固定したトポロジカル順で1〜4頂点、S は空でない全部分集合、指定値0,1,2。計16,857設定 | 条件を満たす523設定に、私有Nim追加による拡張を各5回検査。計2,615回で全て保存 |
| M:必要性の証人 | 条件違反の16,334設定に、私有の小Nim追加による反証を構成 | 全てで少なくとも一つの指定値が変化 |
| R:三個除去の全列挙 | 固定分割で (m,q) = (1,0),(1,1),(1,2),(2,0),(2,1)。計33,801設定 | 全て一致 |
| R:三個・四個除去の乱択 | 五種類のパラメータ、計1,900標本 | 全て一致 |
乱択seedは20260915。R の標本は重複を排除していない。M の検証コードが試す拡張は、U の各局面に私有Nimの山を追加するものに限る。既存局面同士に新しい辺を張る拡張や、新頂点から元の局面へ戻る辺を追加する拡張は、このコードでは検査していない。それらも含む一般性の根拠は上の証明であり、計算は明記した範囲での有限検査である。コードと図の動作も確認した。
M の再現コード
python meta_robust_verify.py で実行。結果はスクリプトと同じ場所に保存する。
"""Check the robust partial-Grundy characterization on all labeled DAGs up to 4 vertices.
The order is fixed; every edge goes from a larger index to a smaller index.
Only standard Python is required. Additional followers are private Nim heaps.
"""
from itertools import product
from pathlib import Path
import json
import random
def grundy(edges, extra):
values = []
for i, followers in enumerate(edges):
# Each k in extra[i] is the value of a private Nim heap option *k.
options = {values[j] for j in followers} | set(extra[i])
value = 0
while value in options:
value += 1
values.append(value)
return values
def first_violation(edges, labels):
for s, c in labels.items():
inner = {labels[t] for t in edges[s] if t in labels}
if c in inner:
return ('same_label', s, None)
for k in range(c):
if k not in inner:
return ('missing_lower', s, k)
for u in edges[s]:
if u not in labels and not any(t in labels and labels[t] == c for t in edges[u]):
return ('missing_return', s, u)
return None
def main():
rng = random.Random(20260915)
report = {'seed': 20260915, 'label_range': [0, 1, 2], 'max_vertices': 4,
'labelled_order': 'edge i -> j allowed exactly when i > j',
'templates': 0, 'valid_certificates': 0, 'random_completions_checked': 0,
'invalid_certificates': 0, 'constructed_counterexamples': 0,
'violation_types': {}, 'by_vertices': []}
for n in range(1, 5):
potential = [(i, j) for i in range(n) for j in range(i)]
count = 0
for edge_mask in range(1 << len(potential)):
edges = [[] for _ in range(n)]
for bit, (i, j) in enumerate(potential):
if edge_mask >> bit & 1:
edges[i].append(j)
for s_mask in range(1, 1 << n):
anchors = [i for i in range(n) if s_mask >> i & 1]
unknown = [i for i in range(n) if not (s_mask >> i & 1)]
for c in product(range(3), repeat=len(anchors)):
labels = dict(zip(anchors, c))
report['templates'] += 1
count += 1
violation = first_violation(edges, labels)
if violation is None:
report['valid_certificates'] += 1
for _ in range(5):
extra = [set() for _ in range(n)]
for u in unknown:
extra[u] = {k for k in range(7) if rng.getrandbits(1)}
got = grundy(edges, extra)
assert all(got[s] == value for s, value in labels.items())
report['random_completions_checked'] += 1
else:
report['invalid_certificates'] += 1
kind, s, witness = violation
report['violation_types'][kind] = report['violation_types'].get(kind, 0) + 1
extra = [set() for _ in range(n)]
if kind == 'missing_lower':
# Every unknown now has an option *k, so none has value k.
for u in unknown:
extra[u] = {witness}
elif kind == 'missing_return':
# Other unknowns cannot equal k; u is forced to k if all
# anchor labels survive. Otherwise robustness already fails.
k = labels[s]
for u in unknown:
extra[u] = set(range(k)) if u == witness else {k}
assert all(k <= max(c) for opts in extra for k in opts)
got = grundy(edges, extra)
assert any(got[s] != value for s, value in labels.items()), (edges, labels, violation, extra, got)
report['constructed_counterexamples'] += 1
report['by_vertices'].append({'vertices': n, 'templates': count})
report['violations_of_theorem'] = 0
report['counterexample_heap_bound'] = 'every added Nim option *k has k <= max prescribed label'
dest = Path(__file__).with_name('meta_robust_results.json')
dest.write_text(json.dumps(report, ensure_ascii=False, indent=2) + '\n')
print(json.dumps(report, ensure_ascii=False, indent=2))
if __name__ == '__main__':
main()
R の再現コード
python meta_structure_verify.py で実行。結果は実行場所に保存する。各仮定を外した反例も含む。
from functools import lru_cache
from itertools import combinations,product
import random,json
def sg(n,edges):
moves=tuple(set(sum(1<<v for v in e) for e in edges))
@lru_cache(None)
def g(mask):
seen={g(mask^e) for e in moves if mask&e==e}
k=0
while k in seen:k+=1
return k
mask=(1<<n)-1
return g(mask),sorted({g(mask^e) for e in moves})
def params(r,m,q):
bs=[set(range(r*i,r*(i+1))) for i in range(m)]
ex=set(range(r*m,r*m+q))
orbits=[]
for a,b in combinations(bs,2):
allv=a|b
for e in combinations(sorted(allv),r):
f=tuple(sorted(allv-set(e)))
if set(e) not in (a,b) and e<f:orbits.append([e,f])
for b in bs:
for e in combinations(sorted(b|ex),r):
if set(e)&ex:orbits.append([e])
return [tuple(sorted(b)) for b in bs],orbits
def instance(r,m,q,bits):
blocks,orbits=params(r,m,q)
return blocks+[e for i,orb in enumerate(orbits) if bits>>i&1 for e in orb]
if __name__=='__main__':
report={'exhaustive':[],'random':[],'examples':{},'seed':20260915}
for r,m,q in [(3,1,0),(3,1,1),(3,1,2),(3,2,0),(3,2,1)]:
bs,orbits=params(r,m,q)
for bits in range(1<<len(orbits)):
es=bs+[e for i,orb in enumerate(orbits) if bits>>i&1 for e in orb]
val,_=sg(r*m+q,es)
assert val==m%2,(r,m,q,bits,val)
report['exhaustive'].append({'r':r,'m':m,'q':q,'count':1<<len(orbits)})
rng=random.Random(20260915)
for r,m,q,count in [(3,2,2,500),(3,3,2,500),(3,4,2,300),(4,2,3,300),(4,3,3,300)]:
bs,orbits=params(r,m,q)
for _ in range(count):
bits=rng.getrandbits(len(orbits))
es=bs+[e for i,orb in enumerate(orbits) if bits>>i&1 for e in orb]
val,_=sg(r*m+q,es)
assert val==m%2,(r,m,q,bits,val)
report['random'].append({'r':r,'m':m,'q':q,'count':count})
# Worked examples. Blocks are A=012 and B=345 unless noted; values are recorded, not asserted.
# r3_transfer: exception E=67 (weight 2 < 3); 670 and 712 lie in E+A, 634 in E+B; m=2, value 0.
# missing_complement: 013 meets A and B, but its complement 245 is absent (condition 3 fails).
# exception_two_blocks: E=6 and the move 603 meets both A and B (condition 4 fails).
# exception_too_large: one block A=012 and E=345 with w(E)=3=W (rho<W fails); 340 and 512 touch E.
# missing_block: the intended block 012 is not a legal move (condition 1 fails); value 0, not 1.
# mixed_size: the weighted example of the text with a,b,c,d,e,z = 0..5 (sg ignores the weights).
examples={
'r3_transfer':(8,[(0,1,2),(3,4,5),(0,1,3),(2,4,5),(6,7,0),(6,3,4),(7,1,2)]),
'missing_complement':(6,[(0,1,2),(3,4,5),(0,1,3)]),
'exception_two_blocks':(7,[(0,1,2),(3,4,5),(6,0,3)]),
'exception_too_large':(6,[(0,1,2),(3,4,0),(5,1,2)]),
'missing_block':(3,[]),
'mixed_size':(6,[(0,1),(2,3,4),(0,2),(1,3,4),(5,0),(5,2),(5,3,4)])
}
for name,(n,es) in examples.items():
value,opts=sg(n,es)
report['examples'][name]={'n':n,'edges':es,'grundy':value,'option_values':opts}
# three_blocks: search for a move meeting three blocks A, B, C=678, which breaks condition 3.
# Optional orbits and triple moves are pruned while the value stays different from 3 mod 2 = 1.
bs,orbits=params(3,3,0)
cross3=list(product(range(3),range(3,6),range(6,9)))
for t in range(10000):
chosen=[orb for orb in orbits if rng.random()<.08]
es=bs+[e for orb in chosen for e in orb]+[e for e in cross3 if rng.random()<.08]
val,opts=sg(9,es)
if val!=1:
# Remove optional core-orbits/triple moves greedily, preserve failed value.
groups=chosen+[[e] for e in es[len(bs)+sum(map(len,chosen)):]]
change=True
while change:
change=False
for i in range(len(groups)):
cand=groups[:i]+groups[i+1:]
nv,_=sg(9,bs+[e for group in cand for e in group])
if nv!=1:groups=cand;change=True;break
es=bs+[e for group in groups for e in group]
val,opts=sg(9,es)
report['examples']['three_blocks']={'n':9,'edges':es,'grundy':val,'option_values':opts}
break
print(json.dumps(report,indent=2))
open('meta_structure_results.json','w').write(json.dumps(report,indent=2))
付録:探索を途中で切り替えた理由
T1 の新規性判定とは独立した、探索過程の記録である。第5版で07節から移した。
ヒント耐性
前の探索で考えた「一個のヒントが消えても一意解」と trade の二重被覆は、Bean–Cavenagh の2026年論文に同じ枠組みがある。小さい盤面の数値や、互いに素な一意解集合との関係も扱われており、今回の主な新規候補から外した。[18]
ライツアウト
一辺変更が最少押下数へ及ぼす大きな影響は Caro–Klostermeyer (2003), Theorem 16 に既存の境界があり、低ランクの辺変更と解集合対応も Batal の式(5)などで研究済みだった。[19][20]弦付きサイクルの具体的分類には調査余地が残るが、今回は任意グラフに適用できる T1 を優先した。
この切替は「候補が間違っていた」というだけの記録ではない。計算や導出が正しくても、既知の成果と一致すれば帰属を修正し、その先に残る問いを選び直すという探索手順の一部である。
出典と照合箇所
- Melissa Huggan & Brett Stevens. Polynomial Time Graph Families for Arc Kayles. Integers 16, A86 (2016).本文確認。§2 のGrundy値、Theorem 1 のequimatchableグラフ、Theorem 2 のline graph対応。通常のゲーム理論と近接するグラフ族の帰属。
- Melissa A. Huggan & Craig Tennenhouse. Genetically Modified Games. Integers 21B, A13 (2021).本文確認。Theorems 4.4–4.5。梯子の既知値と、応手により途中の値を排除する帰納法の近接先行例。4.4 は Winning Ways に帰属している。arXiv 初版では番号が一つずれる。
- Melissa A. Huggan & Craig Tennenhouse. An investigation into the application of genetic programming to combinatorial game theory. arXiv:2102.00476v1 (2021).本文確認。[2] の初版。Theorem 4.5(2×n 梯子の値、Winning Ways 第3巻に帰属)の直後に、tuft を2個まで加えても値は変わらないという証明なしの記述がある。Theorem 4.6 は、四隅のうち3か所または4か所に突起(葉)を付けた梯子の値。角一か所だけの場合はこの定理ではなく、上の tuft の記述の範囲に入る。
- Kyle Burke, Antoine Dailly & Nacim Oijid. Complexity and algorithms for Arc-Kayles and Non-Disconnecting Arc-Kayles. arXiv:2404.10390v2, 2025 11 21改訂(初稿2024)。短縮版は WALCOM 2026, LNCS 16444. DOI.本文確認。Definition 5 / Theorem 6 のedge-disjoint involution(各辺と像が交わらない自己同型)と、その存在判定がグラフ同型問題並みに難しいこと。版により定理番号が異なるため v2 を固定して引用。
- Antoine Dailly, Valentin Gledel & Marc Heinrich. A Generalization of Arc-Kayles. arXiv:1709.05219v3 (2018); International Journal of Game Theory 48, 491–511 (2019). DOI.本文確認。Weighted Arc Kaylesの定義、§4 Proposition 7 / Corollary 2 の複製頂点との同値性。本稿のW1はループなしに限定。
- Stephan Dominique Andres, François Dross, Melissa A. Huggan, Fionn Mc Inerney & Richard J. Nowakowski. The Complexity of Two Colouring Games. Algorithmica 85, 1067–1090 (2023), online 2022 11 24.§2 の strictly matched involution の定義 (SI 1)–(SI 2)。固定点集合は空でもよい。T1の本体の構造に対応するが、論文の対象は別の彩色ゲームである。用語の導入は同論文が引用する2019年の先行研究に帰属する。
- Stephan Dominique Andres, Melissa Huggan, Fionn Mc Inerney & Richard J. Nowakowski. The Orthogonal Colouring Game. Theoretical Computer Science 795, 312–325 (2019). 著者公開原稿.Nowakowskiが公開した著者原稿全文を確認。§3 Theorem 1 は直交彩色ゲームの引分け保証、§5.1 Theorem 7 / Corollary 8 はstrictly matched involutionを持つグラフの特徴付け。出版社版の本文は取得できなかったため、照合対象を著者原稿と明記する。同論文には訂正記事がある。
- Jos W. H. M. Uiterwijk. Construction and investigation of Cram endgame databases. ICGA Journal 40(4), 425–437 (2018).要旨を確認。30マス未満の全盤面サイズの Cram データベースと、空盤面の値が既存文献と一致すること。本文は未取得。
- Ryan Alvarado, Maia Averett, Benjamin Gaines, Christopher Jackson, Mary Leah Karker, Malgorzata Aneta Marciniak, Francis Su & Shanise Walker. The Game of Cycles. arXiv:2004.00776; The American Mathematical Monthly 128(10), 868–887 (2021).本文確認。Theorem 6 の対合と mirror-reverse 戦略。別のゲームにおける「一つだけの例外」の近接例。
- Melissa Amber Huggan. Impartial Intersection Restriction Games. Master's thesis (2015).Arc KaylesとTriple Packingに関連する研究として書誌を確認。本文PDFはサイトの制限で取得できず、検索結果に表示された目次と抜粋のみ確認。全文照合が残る。Triple Packingの交差制限を、互いに素な集合を取る本稿のルールと同一視しない。
- Yonatan Bilu & Nathan Linial. Constructing expander graphs by 2-lifts and discrepancy vs. spectral gap. arXiv:math/0312022.§2 の2-lift構成。正の辺と負の辺をそれぞれ並行・交差する二辺へ持ち上げる対応を確認。T1のゲーム値を主張する文献ではない。
- Jorge Garza-Vargas & Archit Kulkarni. Spectra of infinite graphs via freeness with amalgamation. arXiv:1912.10137v5.§1.3 のwhole-loop / half-loopの区別、Example 1.11、§2.2 Definition 2.2 のlift公式。ペア内辺を「負のループ」と呼ぶ際の規約を確認。
- Stephan Dominique Andres, Melissa A. Huggan, Fionn Mc Inerney & Richard J. Nowakowski. Corrigendum to “The orthogonal colouring game”. Theoretical Computer Science 842, 133–135 (2020).出版社の要旨・検索索引で訂正対象を確認。[7] の Theorem 15(strictly matched involution を持つグラフの同型類の個数の下界)を、より弱い下界に訂正する。
- Hortensia Galeana-Sánchez & Raúl González-Silva. Semi-Grundy function, an hereditary approach to Grundy function. arXiv:1901.04845v1 (2019).§2 のsemi-kernel、Definition 3.1 のsemi-Grundyを確認。Mの十分条件の近接概念であり、応手の発想を新技法として扱わない根拠。
- Aaron N. Siegel. Combinatorial Game Theory. Graduate Studies in Mathematics 146, American Mathematical Society (2013).可逆な選択肢の迂回と標準形を扱う教科書として参照。出版社の索引には reversible の参照頁があるが、書籍本文で M との対応を章節単位に照合したわけではない。
- Michael Lampis & Valia Mitsou. The Computational Complexity of the Game of Set and its Theoretical Applications. arXiv:1309.6504 (2013), LATIN 2014. DOI.二人交互のSETと3-uniform hypergraph Arc Kaylesの関連を確認。一般のハイパーグラフ除去ゲームというモデル自体は既知。
- Endre Boros, Vladimir Gurvich, Nhan Bao Ho, Kazuhisa Makino & Peter Mursic. Tetris Hypergraphs and Combinations of Impartial Games. arXiv:1701.02819v1 (2017).hypergraph Nim の定義とゲーム合成を確認。山サイズ0/1への制限に集合除去ゲームが含まれる。Tetris値や一般のゲームモデルを本稿の新規成果とはしない。
- Richard Bean & Nicholas J. Cavenagh. Defining sets which intersect each Latin trade at least twice. arXiv:2605.28027v1 (2026 05 27).本文確認。k-strong defining set、Lemma 1、Lemma 6、Theorem 4、計算表。ヒント耐性の探索案の主要部分を既知として整理する根拠。
- Yair Caro & William F. Klostermeyer. The Odd Domination Number of a Graph. J. Combin. Math. Combin. Comput. 44, 65–84 (2003).原論文の該当ページを確認。Theorem 2 のサイクルべき、Theorem 16 の一辺削除による最少奇支配数の変化。ライツアウトの大きな変化そのものを新規としない根拠。
- Ahmet Batal. Effects of edge addition or removal on the nullity of a graph. arXiv:2108.03059v2; Discrete Applied Mathematics 357, 56–65 (2024).本文確認。式(5)とその後の解集合対応。辺変更のランク2表現を既知として整理。
第2版の変更記録
提供されたレビューを受け、反例の最小性を頂点数・辺数・連結性に分けて明記し、統合JSONの由来を説明した。追加の別名検索とループ規約の確認を記録し、操作名・添字・図の可読性を修正した。本文の日付は従来の形式を保ち、JSON内は機械処理向けの形式にした。主定理 T1 と系 W1 の仮定・結論・証明は変更していない。
第3版の変更記録
抽象度を上げる探索から、第09節に定理 M と R を追加した。M は任意の非巡回な拡張から指定値を保護する必要十分条件、R は局所的な補集合と例外移送による等重量除去ゲームの定理である。小Nimによる必要性の反証構成、非対称な本体の具体例、独立監査・有限検査・先行研究との境界を記録した。従来の T1 と W1 の証明は維持した。新しい命題も専門家査読・証明支援系による形式検証は未実施。
第4版の変更記録:追加査読の反映
T1 を M へ適用する際、ラベルを残存頂点数だけで定義し、対分けによらないことと、Case C の直後が別の分解で S に入る場合の扱いを明記した。M の計算検査は私有Nim追加に限ると報告範囲を正確にした。M は標準的な議論を選んだ拡張クラスの同値条件として整理する命題と位置づけ、必要性の拡張クラスへの依存を前面に出した。定理の仮定・結論・証明と検証コードの処理は変更していない。
第5版の変更記録:査読と新規性照合の反映
位置づけと構成。主結果 T1 を「命題」から「定理」に、標準的な議論の整理である M を「定理」から「命題」に改めた。冒頭に09節を含む全体の構成を書き、探索切替の記録を付録へ移した。R が T1 と一致する範囲(重み1・W = 2)と、自己同型を仮定しないことが効く範囲を明記した。
新規性照合。[2] の初版に、梯子へ tuft を加える証明なしの記述があることを確認し、葉一枚の場合を「既述の特殊例」とした。第4版の「P₄ に衝突し得る」という評価は、全列挙の結果「計算した範囲では n = 1 でのみ衝突」に修正した。Cram データベース、Game of Cycles、strictly matched involution の訂正記事、可逆な選択肢の標準理論を出典に加えた。
新しい結果。例外集合が三角形の場合の命題 K3 を証明付きで加え、奇数クリークへの予想 K、固定点が二個なら対称でも破れる反例を記録した。対応する検証コードと結果を収録した。
細部。ルール説明の係り方、デモの注記(「*2 を外して」)、実験図の辺が他の頂点に重ならないようにする描画、Case B の図の高さ、静的な説明文とJavaScriptの説明文の食い違い、R の検証コードの例へのコメント、本文の日付表記、参考文献番号の初出順を直した。T1・W1・M・R の仮定・結論・証明と、既存の検証コードの処理結果は変更していない。
第5.1版の変更記録:追加結果の独立監査
提供された第5版をもとに、K3 の証明と R・T1 の対応を独立に確認し、第5版の追加検証コードを再実行して、収録JSONの全フィールドとの一致を確認した。K3 は証明付きの命題、この版の時点では奇数クリーク一般を未証明の予想として保持した。その後、第6版で反例を確認して撤回した。
梯子の二枚・三枚の葉の記述を実際の有限検査範囲へ限定し、固定点クリークの各 (c,m) と試行数を明記した。非クリークの対照実験から必要条件を主張しないこと、例外なしの R から T1 への対応も補った。
初版の tuft の記述をPDF本文で確認した。Game of Cycles の Theorem 6 の面に関する仮定、Cram データベースの収録範囲が未確認であること、訂正記事の参照番号を修正した。日付を YYYY MM DD に統一した。定理 T1・W1・M・R・K3 の結論と検証コードの処理は変更していない。これらの監査は、学術的新規性の確定や証明支援系による形式検証には当たらない。
第6版・完成稿:予想Kの反証と撤回
追加査読の反例指摘を受け、K₅ と3ペアの11頂点例で g = 3(旧予想1)、K₅ と4ペアの13頂点例で g = 2(旧予想0)を確認した。残存頂点・残存辺集合の二方式で、根の値だけでなく全ての一手後の値も照合した。反例の図、完全な辺集合、再現コード、検算結果JSONを収録した。
予想 K の状態を反証済み・撤回へ更新し、冒頭・本文・検査表・今後の課題をそろえた。第5版の標本内で一致した事実は履歴として保持する。T1・W1・K3・M・R の仮定・結論・証明は変更していない。今回は追加の一般化を行わず、この内容を完成稿とする。学術的新規性の確定や証明支援系による形式検証は引き続き未実施である。
第6.1版:新規性表記の精密化
2026 09 16 の再点検で、04節と07節の一マス欠けの扱いを修正した。欠損が端の列にある盤面は、2×(n−1) の梯子の角に葉を一枚付けた形と一致するため、既存の tuft の記述の範囲に含まれる。欠損に関する新規性の候補は内側の列の場合に限定し、その形を「相方が左右の格子をつなぐ切断点になる形」と正確に書き直した。
[3] の Theorem 4.6 が扱うのは四隅のうち3か所または4か所に突起を付けた梯子であることを本文で再確認し、注記を具体化した。tuft が複数の葉を持つ場合に06節の補題を併用することも明記した。T1・W1・K3・M・R の仮定・結論・証明と、検証コード・収録JSONは変更していない(同梱の再現コード6本を再実行し、収録JSONとの一致を確認)。