你以为有 64 种操作?实际只有 30 种——矩阵 A 深度剖析

📅 2026/7/25 10:09:15 👁️ 阅读次数 📝 编程学习
你以为有 64 种操作?实际只有 30 种——矩阵 A 深度剖析

魔表05:矩阵解剖——当线性代数遇见齿轮传动

回顾

在上一篇文章中,我们用 6 个原型向量和三种对称变换 \(R\)\(C\)\(D\),生成了完整的 \(18 \times 64\) 矩阵 \(\mathbf{A}\)。这个矩阵的 64 列对应全部 64 种“按钮-拨轮”基本操作,18 行对应 18 个表盘指针位置。

上一篇文章的末尾写道:

"下一篇,我们将对 \(\mathbf{A}\) 进行深入的数学分析——秩、不变量、可达状态空间,真正理解这个 \(18 \times 64\) 矩阵背后的结构。"

这一篇,我们就来做这件事。而且我们将会看到,矩阵的代数结构恰好映射回了魔表的机械传动原理——数学和物理在这一刻互相印证。


一、64 列中有多少是真正不同的?

上一篇文章中,我们输出了矩阵 \(\mathbf{A}\) 的完整内容。仔细观察输出数据(在上一篇第四节可以查看),一个现象立刻跳了出来:

很多列,一模一样。

下图用不同颜色的矩形框框出了部分相同的列,这样重复的列还有很多,不难找到。

矩阵列向量重复示意

例如前四列(empty 按钮集 × UL/UR/DR/DL 四个拨轮),全部是同一个向量:

\[(1,1,1,1,1,1,1,1,1,\; 11,0,11,0,0,0,11,0,11)^T \]

第 5~8 列(全按按钮集 × UL/UR/DR/DL 四个拨轮),也是完全相同的向量:

\[(1,0,1,0,0,0,1,0,1,\; 11,11,11,11,11,11,11,11,11)^T \]

其他按钮集的情况类似——有些 4 列完全相同,有些呈 2+2 模式(其中两列相同,另外两列也相同)或者 1+3 模式。

我们写一段程序来精确统计。

# 统计 A 中唯一列的数量
unique_cols = {}
for col in range(64):vec = tuple(A[:, col])  # 列向量转元组if vec not in unique_cols:unique_cols[vec] = colprint(f"64 列中, 唯一不同的列共有: {len(unique_cols)} 列")

运行结果:

64 列中, 唯一不同的列共有: 30 列

64 列中只有 30 个是不同的。 这意味着超过一半的列是重复的。不仅如此,按按钮集分组,每个组内 4 个拨轮的等价关系如下:

按钮集 组内等价分划 不同列数
\(\varnothing\) UL ≡ UR ≡ DR ≡ DL 1
\(\{\mathrm{UL},\mathrm{UR},\mathrm{DL},\mathrm{DR}\}\) UL ≡ UR ≡ DR ≡ DL 1
\(\{\mathrm{UL}\}\) UL | UR ≡ DR ≡ DL 2
\(\{\mathrm{UR}\}\) UR | UL ≡ DR ≡ DL 2
\(\{\mathrm{DL}\}\) DL | UL ≡ UR ≡ DR 2
\(\{\mathrm{DR}\}\) DR | UL ≡ UR ≡ DL 2
\(\{\mathrm{UL},\mathrm{UR}\}\) UL ≡ UR | DR ≡ DL 2
\(\{\mathrm{UL},\mathrm{DL}\}\) UL ≡ DL | UR ≡ DR 2
\(\{\mathrm{UL},\mathrm{DR}\}\) UL ≡ DR | UR ≡ DL 2
……(补集遵循相同模式)

规律非常清晰:

  • 全空\(\varnothing\))和全按(四个全按)时,4 个拨轮完全等效 → 各 1 种
  • 其余 14 个按钮集,4 个拨轮分成 2 组,组内等效 → 各 2 种

总计:

\[2 \times 1 + 14 \times 2 = 30 \]

64 种基本操作中,只有 30 种是不同的。


二、按钮与拨轮的联动规律

进一步观察,每个按钮集内部的等价分组有一条统一的规则:

\(\{\text{按下的按钮}\}\) 对应的拨轮彼此等价,\(\{\text{弹起的按钮}\}\) 对应的拨轮也彼此等价。

我们把这个规则称为 P/Q 联动。具体来说,对于任意按钮状态:

定义 \(P = \{\text{按下的按钮对应的拨轮}\}\)\(Q = \{\text{弹起的按钮对应的拨轮}\}\)(按钮与拨轮位置一一对应,共用 UL/UR/DR/DL 标签)。

转动 \(P\) 中的任一拨轮,效果完全相同;转动 \(Q\) 中的任一拨轮,效果完全相同。

用代码验证,所有 16 组均满足:

wheels = ["UL", "UR", "DR", "DL"]for i, label in enumerate(ul_labels):        # 遍历 16 种按钮集# 解析出按下的按钮集合 PP = {w for w in wheels if w in label}    # e.g. {"UL","UR"}Q = set(wheels) - P                      # e.g. {"DR","DL"}# 取出该按钮集的 4 列 (对应 4 个拨轮)cols = {w: A[:, i*4 + k] for k, w in enumerate(wheels)}# 检查: P 内所有拨轮的列是否两两相等p_cols = [cols[w] for w in P]p_ok = all(np.array_equal(p_cols[0], c) for c in p_cols)# 检查: Q 内所有拨轮的列是否两两相等q_cols = [cols[w] for w in Q]q_ok = all(np.array_equal(q_cols[0], c) for c in q_cols)assert p_ok and q_ok, f"P/Q rule failed for {label}!"

验证结果:16 组全部通过。

举几个具体例子来看:

  • \(S = \{\mathrm{UL}\}\)\(P = \{\mathrm{UL}\}\)\(Q = \{\mathrm{UR}, \mathrm{DR}, \mathrm{DL}\}\)。转 UL 独成一类;转 UR、DR、DL 三者效果相同。
  • \(S = \{\mathrm{UL}, \mathrm{UR}\}\)\(P = \{\mathrm{UL}, \mathrm{UR}\}\)\(Q = \{\mathrm{DR}, \mathrm{DL}\}\)。转 UL 和 UR 等价;转 DR 和 DL 等价。
  • \(S = \varnothing\)\(P = \varnothing\)\(Q = \{\mathrm{UL}, \mathrm{UR}, \mathrm{DR}, \mathrm{DL}\}\)。全部拨轮属于 \(Q\),四个全等 → 退化为 1 种。
  • \(S = \{\mathrm{UL},\mathrm{UR},\mathrm{DR},\mathrm{DL}\}\)\(P = \{\mathrm{UL}, \mathrm{UR}, \mathrm{DR}, \mathrm{DL}\}\)\(Q = \varnothing\) 。四个拨轮全等 → 退化为 1 种。

三、对应机械结构:P/Q 联动

上一节总结的数学规律,是真的吗?拿出魔表实物来验证。

观察魔表的传动机制,你会发现:

  • 按下的按钮会将对应的拨轮与一个共同的齿轮组连接起来。因此,转动 \(P\) 中任何一个拨轮,都会通过这个齿轮组驱动所有按下的按钮所对应的表盘,效果完全相同。
  • 弹起的按钮则与另一个齿轮组相连。转动 \(Q\) 中任何一个拨轮,同样会通过该齿轮组统一传动。

于是,在一个固定的按钮状态下,四个拨轮被分成两个功能等价组。转动同一组内的任意拨轮,对表盘的影响完全一致。这就是矩阵中等价列的物理根源。

用魔表圈的术语,弹起按钮对应的拨轮称为 F 轮,按下按钮对应的拨轮称为 B 轮。本文后续将使用这一约定。

F 轮:弹起的按钮所对应的拨轮(\(Q\) 类)

B 轮:按下的按钮所对应的拨轮(\(P\) 类)

回顾上面的等价关系表,用 F/B 语言描述:

  • \(\varnothing\)(全弹):全部是 F 轮,四个 F 轮等效 → 1 种操作
  • \(\{\mathrm{UL},\mathrm{UR},\mathrm{DL},\mathrm{DR}\}\)(全按):全部是 B 轮,四个 B 轮等效 → 1 种操作
  • 其余 14 组:既有 F 轮又有 B 轮,各 2 种

这一结论在网上的魔表研究中也得到了独立验证。blueten 在 《用矩阵探索魔表的复原》 一文中,直接从机械角度得出了完全一致的结论:

"16 种立柱状态中,除了 all 只有 B 轮、ALL 只有 F 轮以外,其他 14 种状态都同时存在 F 轮和 B 轮,因此外轮一共有 30 种转动方法。"

我们的分析路径是“先看矩阵数据 → 归纳数学规律 → 再对实物验证”,而 blueten 是“从机械原理直接推导”。两种不同的路径,得出了完全一致的结论——数学结构就是机械结构的忠实映射


四、角部的硬连接

除了 P/Q 联动,矩阵中还隐藏着另一条简洁的规律。

我们固定一个拨轮(比如 UL),遍历全部 16 种按钮状态,检查该拨轮对四个角部位置的影响是否一致。换句话说:

只换按钮、不换拨轮,角部位置的值会不会变?

wheels = ["UL", "UR", "DR", "DL"]# 定义四个角部位置:拨轮 k → (正面角索引, 反面角索引)
corner_map = {"UL": ("F1", 0, "B3", 11),   # k=0: F_1 在向量索引 0, B_3 在 11"UR": ("F3", 2, "B1", 9),    # k=1: F_3 在索引 2, B_1 在 9"DR": ("F9", 8, "B7", 15),   # k=2: F_9 在索引 8, B_7 在 15"DL": ("F7", 6, "B9", 17),   # k=3: F_7 在索引 6, B_9 在 17
}for k, w in enumerate(wheels):f_name, f_idx, b_name, b_idx = corner_map[w]# 遍历 16 种按钮状态, 取该拨轮对应的列f_vals = [A[f_idx, i*4 + k] for i in range(16)]b_vals = [A[b_idx, i*4 + k] for i in range(16)]# 全部应为 +1 (1) 和 -1 (11)f_ok = all(v == 1  for v in f_vals)b_ok = all(v == 11 for v in b_vals)print(f"转 {w} 轮: {f_name}={f_ok}, {b_name}={b_ok}")

运行结果:

转 UL 轮: F1=True, B3=True
转 UR 轮: F3=True, B1=True
转 DR 轮: F9=True, B7=True
转 DL 轮: F7=True, B9=True

全部为 True。结论非常明确:

只要转的是 正面这个角一定是 反面这个角一定是
UL 拨轮 \(F_1 = +1\) \(B_3 = -1\)
UR 拨轮 \(F_3 = +1\) \(B_1 = -1\)
DR 拨轮 \(F_9 = +1\) \(B_7 = -1\)
DL 拨轮 \(F_7 = +1\) \(B_9 = -1\)

与按钮状态完全无关。 换句话说,角部指针与拨轮之间存在着固定的对应关系:顺时针转 UL 轮,\(F_1\) 一定 \(+1\)\(B_3\) 一定 \(-1\)——无论按钮怎么按,这个对应关系都不会消失。当然,由于上一节讨论的 P/Q 联动,\(F_1\) 也可能在转动其他拨轮(与 UL 同属一个等价类的轮)时获得 \(+1\)。但 UL 轮对 \(F_1\) 的直接驱动始终存在,不会被按钮切断。

blueten 的文章中也写明了这一点:“角上的指针都是互相关联的,因此实际上我们只需要关注 14 个指针的变动。”——与我们的结论完全一致。


五、18 维空间的结构分解

综合以上分析,我们可以将 18 维状态空间做一个清晰的结构分解。

5.1 角部(8 维)

如上节所述,每个拨轮对特定的角部指针有固定的直接驱动关系(如 UL 轮 → \(F_1=+1,\;B_3=-1\)),这一关系始终成立、不受按钮状态影响。但角部指针的实际运动还受 P/Q 联动影响——它们也可能在同组其他轮转动时被间接带动。

而在这 8 维中还存在 4 个不变量。检查矩阵 \(\mathbf{A}\) 的所有 64 列,可以发现无论哪种操作,以下关系始终成立:

\[\begin{aligned} B_1 + F_3 &\equiv 0 \pmod{12} \\ B_3 + F_1 &\equiv 0 \pmod{12} \\ B_7 + F_9 &\equiv 0 \pmod{12} \\ B_9 + F_7 &\equiv 0 \pmod{12} \end{aligned} \]

这四条约束把角部的 8 个自由度压缩到 4 个有效自由度

5.2 非角部(10 维)

除去 8 个角部位置,剩余 10 个位置是真正随按钮状态变化的"可变分量":

\[F_2,\; F_4,\; F_5,\; F_6,\; F_8,\; B_2,\; B_4,\; B_5,\; B_6,\; B_8 \]

我们从 30 个唯一列中抽出这 10 行,构成一个 \(10 \times 30\) 的子矩阵,计算它的秩:

# 从 30 个唯一列中抽取非角部 10 行
corner_idx = [0, 2, 6, 8, 9, 11, 15, 17]    # 角部位置索引
non_corner_idx = [i for i in range(18) if i not in corner_idx]
M = A_unique[non_corner_idx, :]              # 10 × 30 子矩阵print(f"非角部子矩阵: {M.shape}, rank = {np.linalg.matrix_rank(M)}")
# 输出: 非角部子矩阵: (10, 30), rank = 10

秩 = 10 = 行数,这是满行秩。回顾线性代数的结论:

对于 \(M\mathbf{k} = \mathbf{y}\),其中 \(M\)\(m \times n\) 矩阵,秩为 \(r\)

  • 有解当且仅当 \(\mathbf{y}\) 落在 \(M\) 的列空间中。若 \(r = m\)(满行秩),则列空间 = 整个 \(\mathbb{R}^m\)任意 \(\mathbf{y}\) 都有解
  • 解唯一当且仅当核空间维数 \(n - r = 0\),即满列秩。这里 \(n = 30\)\(r = 10\),核空间维数 = \(20\),所以解不唯一——有无穷多种操作组合能达到同一目标。

因此:

给定任意的 10 个目标值,总能找到操作组合精确实现它;而且解法远不止一种。非角部指针是"完全独立可控"的。

用随机目标验证:

for _ in range(5):target = np.random.randint(0, 12, 10)   # 随机目标状态k = np.linalg.lstsq(M, target)[0]       # 求操作系数result = np.round(M @ k).astype(int) % 12assert np.all(result == target)          # 全部精确命中

5 次随机目标,5 次精准命中。

注:以上分析在实数域上进行。 \(\mathbb{Z}_{12}\) 不是域,秩满行不严格保证 \(\mathbb{Z}_{12}\) 上有解。但矩阵元素仅含 \(0, \pm 1\)、结构高度规整,随机验证也全部通过——经验上确认 \(\mathbb{Z}_{12}\) 中同样满秩。严格证明需要模论工具,此处不再展开。

5.3 总结图

graph TDS[18 维状态空间]S --> C[角部 8 维]S --> N[非角部 10 维]C --> C1[4 维有效自由度<br/>由拨轮直接控制]C --> C2[4 维约束<br/>B₁+F₃=0, B₃+F₁=0<br/>B₇+F₉=0, B₉+F₇=0]N --> N1[10 维全部可控<br/>满秩]

矩阵 \(\mathbf{A}\) 的总秩 = \(4 + 10 = 14\)

进一步,如果我们去掉背面四个角(\(B_1, B_3, B_7, B_9\)),只关注剩余的 14 个指针(全部正面 9 个 + 反面 5 个非角部),这 14 维子矩阵的秩同样是 14——满秩。这意味着:

这 14 个指针的任意排布都是可达的。 而背面四个角无需主动控制——它们被四个不变量锁死:\(B_1 = -F_3\)\(B_3 = -F_1\)\(B_7 = -F_9\)\(B_9 = -F_7\)只要把 14 个可控指针复原到位,背面四角自动归位。

这也解释了为什么 blueten 在机械分析中只关注 14 个指针——其余 4 个是冗余的,由不变量唯一确定。

5.4 简化后的矩阵 A

简化后的矩阵A

经过简化,我们最终最简洁的矩阵 \(A\) 如图所示,矩阵大小 \(14 \times 30\)。这将大大简化我们的计算。


六、原型还能再简化吗?

在第三篇中,我们确立了 6 个原型——v0 到 v5。当时只有 \(R\)\(C\)\(D\) 三种对称变换,\(R\) 会改变拨轮(UL → UR → DR → DL),所以在固定 UL 拨轮的前提下,能用的生成手段只有 \(C\)\(D\)。6 个原型在这个框架下两两之间无法互推,因此都是必需的。

但现在我们有了 P/Q 联动。它打通了一条新的推导路径:\(R\) 变换后的向量,有时也等于一个 UL 拨轮的向量。

6.1 v3 = R(v2)

以 v2 和 v3 为例。回顾第三篇中它们的定义:

\[\begin{aligned} v_2 &= E(\{\mathrm{UR}\},\, \mathrm{UL}) \quad &P=\{\mathrm{UR}\},\; Q=\{\mathrm{UL},\mathrm{DR},\mathrm{DL}\} \\ v_3 &= E(\{\mathrm{DR}\},\, \mathrm{UL}) \quad &P=\{\mathrm{DR}\},\; Q=\{\mathrm{UL},\mathrm{UR},\mathrm{DL}\} \end{aligned} \]

现在对 v2 施加 \(R\) 变换:

\[R(v_2) = E(\{\mathrm{DR}\},\, \mathrm{UR}) \]

这是 \(R\) 对称性的标准结论——按钮集和拨轮同时旋转。此时按钮集为 \(\{\mathrm{DR}\}\),P/Q 划分为 \(P = \{\mathrm{DR}\}\)\(Q = \{\mathrm{UL}, \mathrm{UR}, \mathrm{DL}\}\)。注意 UR 和 UL 同在 Q 中——由 P/Q 联动,转 UR 和转 UL 效果相同:

\[E(\{\mathrm{DR}\},\, \mathrm{UR}) = E(\{\mathrm{DR}\},\, \mathrm{UL}) = v_3 \]

因此:

\[\boxed{R(v_2) = v_3} \]

经代码验证,两者模 12 下完全相等,18 个分量一一吻合。

6.2 从 6 到 5

v3 既然可以从 v2 通过 \(R\) 推导出来,它就不再需要单独测量了。6 个原型缩减为 5 个

\[\text{保留:}\; v_0,\; v_1,\; v_2,\; v_4,\; v_5 \qquad \text{冗余:}\; v_3 = R(v_2) \]

6.3 总结

原始 简化后 依据
基本操作 64 种 30 种不相同 P/Q 联动:组内 F 轮等价、B 轮等价
独立指针 18 个 14 个(去掉背面四角) 不变量:\(B_1=-F_3\) 等四个约束
原型数 6 个 5 个(v0, v1, v2, v4, v5) v3 = R(v2),由 P/Q 联动打通
14 14(不变) 去重不改变列空间

数学模型没有”变小“——秩始终是 14。但我们搞清楚了哪些是冗余的、为什么冗余,同时与机械传动关系进行了相互印证。


七、结语

本文对 \(\mathbf{A}\) 矩阵做了系统分析,得出四条核心结论:

规律 数学发现 机械对应
P/Q 联动 64 列去重为 30 列,每组内 F 轮等价、B 轮等价 按下/弹起按钮通过齿轮组联动对应拨轮
角部硬连接 拨轮对角部指针有固定驱动关系(如 UL→\(F_1\)=\(+1\), \(B_3\)=\(-1\)),始终成立 角部指针通过齿轮直接连在对应拨轮轴上
空间分解 14 维可控(全部正面 + 反面 5 个非角部),4 个背面角由不变量确定 14 维有效自由度 + 4 个自动归位的指针
原型简化 6 个原型减为 5 个(v3 = R(v2)),P/Q 联动打通了新的推导路径 同一对角位置的关系只需测一次即可

这四条规律,条条都是从矩阵数据出发归纳出来的,然后回到实物验证时精确吻合。这说明我们通过构建数学模型完美捕捉到了魔表物理结构的本质。

下一篇,我们将基于简化后的 14 维有效模型,讨论具体的求解算法——如何从给定的打乱状态出发,计算出一组可操作的基本操作序列。


参考资料

blueten,《用矩阵探索魔表的复原》,魔方吧·中文魔方俱乐部,2021.

链接:http://bbs.mf8-china.com/forum.php?mod=viewthread&tid=116206