Skip to content

算法Algorithm

Myers 位向量编辑距离

Myers bit-vector edit distance · Myers 1999 algorithm · 差分位向量编辑距离

用两个差分位向量与一项末行分数逐列推进单位编辑距离,明确全局和自由文本前缀边界,并处理跨字加法进位。

形式陈述 ​

读到一段文本的末尾时,一个固定模式与它“最接近”到了什么程度?如果忽略文本开头的无关部分,答案又会怎样变化?本页维护的是每个文本边界上的精确费用,不恢复匹配起点或编辑脚本。

设模式 P[0..m)、文本 T[0..n) 在同一有限字母表上。插入、删除、替换各费用为 1,相等配对免费,不允许把交换邻字当作一次操作。使用单位编辑距离网格的内部递推

C[i,j]=min{C[i−1,j]+1, C[i,j−1]+1, C[i−1,j−1]+[P[i−1]≠T[j−1]]}.

固定一种边界模式,令 β∈{0,1}:

C[i,0]=i,C[0,j]=βj.
  • global,β=1:C[m,j]=d(P,T[0..j)),即模式与整个已读前缀的距离。
  • infix,β=0:C[m,j]=min0≤s≤jd(P,T[s..j))。文本前缀可以免费略过,候选后缀必须结束在当前边界;也允许 s=j 的空后缀。

第二种含义可从网格直接证明:第零行任意位置都可作为零费用起点,之后按同样三类边改写模式。取所有起点的最小值,恰好得到上述最小后缀距离。这不是允许任意丢弃模式前后两端的局部比对。

对 m>0,令第 i−1 位对应第 i 行,用两个 m 位向量保存垂直差分:

(Pv)i−1=[C[i,j]−C[i−1,j]=1],(Mv)i−1=[C[i,j]−C[i−1,j]=−1].

另存末行分数 S=C[m,j]。初始 Pv 的全部有效位为一,Mv=0,S=m。差分为零的位置两个位都为零;同一位置不能同时置一。

像Shift-And 的字符掩码那样,预处理 E(c),在 P[i]=c 的位置置一。本页参考程序只接收字面字节模式;相似的掩码外形不意味着两算法的状态相同。每读符号 c,设 E=E(c),依次计算

Xv=E|Mv,Xh=(((E&Pv)+Pv)⊕Pv)|E,Ph=Mv|¬(Xh|Pv),Mh=Pv&Xh.

这里 ⊕ 是按位异或。Ph,Mh 编码新旧列之间的水平差分,尚未移位时先更新

S←S+(Ph)m−1−(Mh)m−1.

再令 P^h=(Ph≪1)|β、M^h=Mh≪1,得到下一列

Pv′=M^h|¬(Xv|P^h),Mv′=P^h&Xv.

全部向量只保留低 m 位,加法按模 2m 理解。一个字装不下时,以 q=⌈m/w⌉ 个字模拟这些操作;加法进位和移位进位都必须跨字传递。这是Word-RAM上的 O(q) 次字操作,不是任意精度整数上的无条件常数时间。

直觉

数值很大,相邻差却只有三种 ​

单位编辑操作保证相邻两行、相邻两列的值相差至多一。多一个模式字符,至多多付一次删除;反过来删掉这个字符也至多改变一次费用。文本多一个字符时同理。自由前缀模式取所有后缀的最小值:非空最优后缀去掉最后字符仍是上一边界的候选;若最优后缀为空,其费用为 i,而上一边界也可选空后缀。两个方向的界仍成立。

所以垂直、水平差分都属于 {−1,0,1}。从第零行的已知值出发累加垂直差分,可以重建整列。扫描不必每步实际累加它们,因为末行分数只需加上新一列最下面的水平差分。这也是必须在移位前检查第 m−1 位的原因。

从一个格子推到整列 ​

取一个格子的左上角值为 a,左下角为 a+v,右上角为 a+h,相等标记为 e∈{0,1}。令 t=min{−e,v,h},右下角按网格递推等于 a+1+t。因此输出差分为

v′=1+t−h,h′=1+t−v.

输入只有 3×3×2=18 种。把正、负差分分别编码成两个布尔量,逐项代入上式,可以得到:令 xv=e∨[v=−1],则

[v′=1]=[h=−1]∨¬(xv∨[h=1]),[v′=−1]=[h=1]∧xv.

交换横竖角色,就得到 Ph,Mh 的对应公式。参考程序把全部18种输入逐一与数值递推核对。整列先由旧垂直差分求出水平差分,再把水平差分向下一行移动,转成新垂直差分。第零行的水平差分恰是 β,所以移入 P^h 最低位的是 β,而不是一条不问边界的固定常数。

一次加法为何能解决行间依赖 ​

难点在于第 i 位所需的 Xh 还依赖前一行的负水平差分。用从零开始的位下标,记旧 Pv 的位为 pi、相等位为 ei,则需要的传播规则是

xi=ei∨ci,c0=0,ci+1=pi∧(ei∨ci).

这恰好是一条二进制进位链。把 Pv 与 E&Pv 相加:第二个加数的位 eipi 不会在 pi=0 处产生进位,故加法输出进位就是上式的 ci+1。该位和为 pi⊕(eipi)⊕ci;再异或 pi 并或上 ei,当 ei=1 时得到一,当 ei=0 时得到 ci,结果正是 xi。

于是算术加法同时完成了这条有限状态传播。这里需要进位沿连续正差分传播;不能套用“并行字段之间总要隔离进位”的直觉把它截断。最高位之外的进位可以丢弃,因为它不再影响任何有效行。

这三个层次连成归纳证明:初始差分正确;逐格布尔式等价于网格递推;进位链一次算出所有需要的横向条件;移位注入正确边界后得到下一列,末行分数也同步更新。因而每一步返回的都是所声明模式的精确费用。

差分列、跨字加法与边界注入
例子与边界

先看一个确实跨字的加法 ​

取 P=abbb、w=3,初始 Pv=[111,001]、Mv=[000,000]、S=4。读 a 时 E=[001,000],字数组按低字在前排列。

低字加法是 001+111=1000:保存低三位 000,向高字传一。高字于是算 000+001+1=010。异或旧 Pv 并或上 E,清掉第四行以外的填充位后得到 Xh=[111,001]。末行的负水平差分为一,分数从 4 降到 3,对应保留 a、删除三个 b。

若在每个字都把输入进位重置为零,高字会算成 000+001=001,其 Xh 有效位变为零,错误地返回 4。这不是“大例子才有”的整数溢出问题,而是在第四个模式位置就能复现的依赖丢失。

同一文本,两种边界 ​

令 P=ababa,流入文本 zzababa,仍用 w=3。两个字的有效掩码是 [111,011];末行对应高字的第二位,不是三位字的最高位。

文本边界 j 刚读字符 global 分数 infix 分数
0 空 5 5
1 z 5 5
2 z 5 5
3 a 4 4
4 b 3 3
5 a 2 2
6 b 3 1
7 a 2 0

global 必须为前面的两个 z 付费,最终距离为二;infix 可以从边界二开始,最终后缀 ababa 完全匹配。若允许至多一次编辑,infix 的合格端点是 6,7,global 没有合格端点。

在 infix 的第 3 步,初始正差分仍全为一,E=[101,010]。低字算 101+111=1100,把进位传到高字,最终 Xh=[111,011];Ph=[000,000]、Mh=[111,011]。分数减一后,把 Mh 左移得到 [110,011],把 Ph 左移并注入零仍是 [000,000]。新 Pv=[110,011],Mv=0,重建列为

C[0..5,3]=[0,0,1,2,3,4].

最终 infix 列为 [0,0,1,0,1,0],两个差分向量是 Pv=[010,001]、Mv=[100,010]。global 最终列则为 [7,6,5,4,3,2],全部有效垂直差分为负。下载结果逐列保存完整核对值。

端点不是起点,费用不是脚本 ​

模式 ab 对文本 acb,在末边界 3 的 infix 分数为一。后缀 acb 可以插入 c 得到,后缀 cb 可以替换首字母得到;两个不同起点都达到最小值。一个分数不能决定选哪一条解释。本页也没有保存历史列的前驱,不能把这些输出称作已重建的编辑脚本。

m=0 时 global 返回 j,infix 返回零,直接按边界处理,不读取不存在的最高位。任意 m 下,初始 j=0 分数都是 m。阈值 k≥m 时 infix 每个边界都合格,因为空后缀总是候选;因此“报告一个合格端点”也不保证找到了非空片段。

边界的一位之差可以用 P=a,T=ba 验证:global 最终为一,infix 为零。如果把两种模式都固定注入一,后者就悄悄变成前者。

推论与应用

时间按实际字数计,输出另算 ​

设字母表大小为 σ,q=⌈m/w⌉。参考程序先建立 σ 行的掩码表,再逐位置置位,编译时间为 O(m+σ(q+1)+1)。每个非空模式的扫描步骤包含常数趟长度 q 的布尔、加法和移位循环,因此是 O(q) 个字操作。扫描全文并保存每个新边界的分数,统一耗时

O(m+σ(q+1)+n(q+1)+1).

掩码表、当前差分、临时数组与单步诊断记录共占 O(σ(q+1)+q+1) 个字;feed 返回的 n 项分数另占 O(n)。step 不保存旧文本或全部历史。column() 是额外的 O(m+1) 时间与空间诊断操作,不能在每字节都调用它后仍声称扫描仅用 O(nq)。

实现把向量拆成宽度1至63的字,加法中间数至多多一位;小宽度用于测试跨字传递。位置和分数不超过63位非负整数,模式最多4096字节。参数、字节、块类型和位置上限均在改动状态前检查。理论模型要求地址与计数器可放入机器字,不能把调试用的一位逻辑块宽当成整台机器的地址宽度。

它利用的不是小编辑数 ​

本算法的扫描成本不乘阈值 k,也不依赖实际最小费用很小:无论最终分数是多少,每个符号都推进整列差分。它与Myers 1986 最短插删前沿同属一个作者的工作,却是不同算法。1986方案按编辑次数扩展最远对角位置,允许插入和删除;本页1999方案打包相邻差分,包含费用一的替换。例如 a 到 b 在本页费用一,在仅插删模型中费用二。

改变费用或加入转置,需要重新推导差分范围与格子逻辑。删除费用二时,初始垂直差分已经是二,两个仅编码 −1,0,1 的向量无法原样表示。把阈值检查换一个数不能修复这种状态不充分。带状算法、期望时间剪枝和脚本重建也不包含在这份全列接口里。

参考程序另用普通标量网格逐列比较全部数值,覆盖两种边界、空模式、跨字长度与分块输入;结果文件保留上述轨迹和被击穿的快捷写法。终点任务要求从位向量重建一列,再用独立网格验证分数,而不只接受一个最终整数。

参考资料
  • Gene Myers, “A Fast Bit-Vector Algorithm for Approximate String Matching Based on Dynamic Programming”, Journal of the ACM 46(3), 1999, pp.395–415:论文记录,原文副本。§§2–3给出自由文本前缀边界、三值差分、布尔格子转移、加法传播及基本算法;§3中的边界说明支持本页两种第零行设置。这里实现§3.7的多字向量模拟,不借用后续带状扩展的期望时间结论。
关系图谱8 个相邻概念 · 2 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组
类型化关系