Iter-4360dd15-0174-fact-exhaustive-reachability-audit

fact 4360dd15 predicate verification reachability audit local insertion

修改:20260424233953000

迭代 174:accept(S,L,r) 与“插入后一次相邻交换可达性”的小规模穷举对账

本轮作为 critic,直接攻击当前判定最可疑的失败点:
accept(S,L,r) 是否只是一个“看起来合理”的局部规则,而不是对“插入后一次相邻交换”可达性的真实刻画。

结论


在小规模穷举里,没有找到反例:

- alphabet size = 1, 2, 3
- |S| = 0..4
- 全部 L 满足 |L| = |S| + 1

对比
- accept_candidate(S, L):当前规则(SL 的子序列,或 L 经过一次相邻交换后使 S 成为子序列)
- reachable_by_insert_then_swap(S, L):显式枚举“先插入一个符号,再做零次或一次相邻交换”

两者在上述穷举域内完全一致:
- **false positive = 0**
- **false negative = 0**

可复现代码


from itertools import product

def is_subsequence(short, long):
it = iter(long)
try:
for x in short:
while next(it) != x:
pass
return True
except StopIteration:
return False

def accept_candidate(short, long):
if len(long) != len(short) + 1:
return False
if is_subsequence(short, long):
return True
n = len(long)
for i in range(n - 1):
l = list(long)
l[i], l[i+1] = l[i+1], l[i]
if is_subsequence(short, l):
return True
return False

def reachable_by_insert_then_swap(short, long, alphabet):
n = len(short)
if len(long) != n + 1:
return False
for p in range(n + 1):
for sym in alphabet:
base = list(short[:p]) + [sym] + list(short[p:])
if tuple(base) == long:
return True
for i in range(n):
l = base[:]
l[i], l[i+1] = l[i+1], l[i]
if tuple(l) == long:
return True
return False

for k in [1, 2, 3]:
alphabet = tuple('abc'[:k])
for n in range(0, 5):
for short in product(alphabet, repeat=n):
for long in product(alphabet, repeat=n + 1):
assert accept_candidate(short, long) == reachable_by_insert_then_swap(short, long, alphabet)

作为审稿人的挑刺


这不是证明,只是把最容易出错的“局部可达性”部分先打穿了。
当前最可疑的残余风险不在 一次相邻交换 本身,而在**语义假设**:

- 我们默认“插入”只关心 token 序列,而不关心插入符号是否是 fresh marker;
- 我们默认 content-token 的顺序就是全部判据;
- 我们默认相邻交换不需要额外约束(例如同义词、停用词、标点、词形变化)。

如果这些前提有一个是假的,那么 accept(S,L,r) 仍可能在真实文本上失效,即使在抽象 token 模型里它是对的。

结论(批判版)


当前最危险的不是“窗口边界”了,边界已经被穷举清理掉;
真正悬着的,是 token 模型是否过度简化自然语言插入语义