ヴァーヘフアルゴリズム

ヴァーヘフアルゴリズム(Verhoeff algorithm)とは、オランダ人数学者ヤコブス・ヴァーヘフによって開発された、誤り検出のためのチェックサム計算式であり、1969年に初めて発表された。ヴァーヘフアルゴリズムは全ての1桁誤りと隣接する2桁の入れ替わり誤りを検出できる最初の十進チェックデジットアルゴリズムであり、当時は1桁の十進コードでは不可能であると考えられていた。

目的
ヴァーヘフは、全ての1桁誤りと隣接する2桁の入れ替わりを検出する1桁の十進コード(1桁の十進の数字であるチェックデジット)を見付けるという目標を持っていた。当時はそういったコードが存在しないという想定の証明により、例えばISBNのチェックデジットなどにおいて、十一進コードが一般的であった。

ヴァーヘフの目標は実地的でもあった。オランダの郵便システムから得た実データを使い、異なる種類の誤りに対する重み付き配点システムを使って異なるコードを評価して、それを基にした。ヴァーヘフによる分析では、誤りを複数のカテゴリーに分類した:まず何桁が誤っているのか、さらに2桁の場合、入れ替わり(ab → ba)、双子(aa → bb)、飛び越え入れ替わり(abc → cba)、音声的(1a → a0 (例えばオランダ語で17と70はそれぞれ/ˈzeːvə(n)tin/と/ˈzeːvə(n)təx/))、そして飛び双子(aba → cbc)に分けられた。さらに数字の欠落や追加もあった。ただし、一部の種類の誤りが起きる確率は小さいかもしれず、また一部のコードは1桁誤りと入れ替わりを検出するという主目的に加えてそういった誤りに対して耐性があった。

音声的な誤りは特に言語による影響が見られた。これはオランダ語において文字は2桁1組で読まれるためであった。またオランダ語で50は15と発音が似ているが、80は18とは発音が似ていない。

6桁の数字を例に取ると、ヴァーヘフは以下のように誤りの分類を報告している。
 誤りの桁数 分類 件数 頻度1転写9,57479.05%2入れ替わり1,23710.21%双子670.55%音声的590.49%その他隣接2321.92%飛び越え入れ替わり990.82%飛び越え双子350.29%その他飛び越え誤り430.36%その他980.81%31691.40%41180.97%52191.81%61621.34%計 12,112

解説
ヴァーヘフは位数10の二面体群(10要素に対する非可換な演算の系であり、正五角形の回転と反転に対応する)の性質を元に、置換を組み合わせてアルゴリズムを考案した。ヴァーヘフは、これは二面体群の初の実用的応用であり、全ての美しい数学には最終的には用途が見付かるという原則を確認したと主張した。もっとも、実際にはアルゴリズムは単純なルックアップテーブルによって実装され、元となる群と置換の理論からどうやってその表を生成するのか理解する必要はない。

ヴァーヘフアルゴリズムはより適切にはアルゴリズムの族であると考えられる。なぜならこの他の置換も考えられ、ヴァーヘフの論法で考察されているためである。ヴァーヘフはこの特定の置換
は、95.4%の音声的誤りを検出するという特性を持っているため、特別であると記している。Verhoeff 1969, p. 95

このアルゴリズムの強みは、全ての誤字と入れ替わり誤りと、ほとんどの双子・飛び越え双子・飛び越え入れ替わり・そして音声的誤りを検出する点である。

ヴァーヘフアルゴリズムの主な弱みは複雑さと、必要な計算が手で簡単にできない点である。類似するコードはダムアルゴリズムであり、似た性質を持つ。

 表に基づくアルゴリズム 
ヴァーヘフアルゴリズムは3つの表を使って実装できる: 積表d・逆元表inv・そして置換表pである。

 d(j,k)Verhoeff 1969, p. 83 k  0  1  2  3  4  5  6  7  8  9  j  0 0  1 2  3 4  5 6  7 8  9 1 1 2  3 4  0 6  7 8  9 5 2 2 3  4 0  1 7  8 9  5 6 3 3 4  0 1  2 8  9 5  6 7 4 4 0  1 2  3 9  5 6  7 8 5 5 9  8 7  6 0  4 3  2 1 6 6 5  9 8  7 1  0 4  3 2 7 7 6  5 9  8 2  1 0  4 3 8 8 7  6 5  9 3  2 1  0 4 9 9 8  7 6  5 4  3 2  1 0

     inv(j)  j  0 0 1 4 2 3 3 2 4 1 5 5 6 6 7 7 8 8 9 9

 p(pos,num) num  0  1  2  3  4  5  6  7  8  9  pos (mod 8)  0 0  1 2  3 4  5 6  7 8  9 1 1 5  7 6  2 8  3 0  9 4 2 5 8  0 3  7 9  6 1  4 2 3 8 9  1 6  0 4  3 5  2 7 4 9 4  5 3  1 2  6 8  7 0 5 4 2  8 6  5 7  3 9  0 1 6 2 7  9 3  8 0  6 4  1 5 7 7 0  4 6  9 1  3 2  5 8

最初の表dは、二面体群D5の積に基づくものであり、単にその群のである。この群は可換ではない、つまりある値jとkに対して、d(j,k) ≠ d(k, j)であることに注意せよ。

逆元表invは数字に対して積における逆元、つまりd(j, inv(j)) = 0を満す数を表す。

置換表pは各数字に対して、数値の中における位置を元に、置換を適用する。これは実際には単一置換(1 5 8 9 4 2 7 0)(3 6)を繰り返し適用したものである。つまり、p(i+j,n) = p(i, p(j,n))である(参考: 

ヴァーヘフチェックサムの計算は次のように実行される:

 数値の各桁から配列nを作成する。桁は右から左へ取る(最も右の桁がn0,となる)。
 チェックサムcを0に初期化する。
 配列nの各添字i(0から始まる)に対して、cをd(c, p(i mod 8, ni))で置き換える。

元の数値はc = 0となるとき、かつそのときのみ妥当である。

チェックデジットを生成するには、0を末尾に追加して上記の計算をする。すると正しいチェックデジットはinv(c)となる。

 例 

236に対するチェックデジットの生成:
 i ni p(i,ni) c0000163323313212
cは2であるので、チェックデジットはinv(2)つまり3となる。

2363のチェックデジットの検証:
  i  ni  p(i,ni) c0333163123343210
cは0であり、チェックデジットは正しい。

 参考文献 

外部リンク

 Detailed description of the Verhoeff algorithm
 A description using lookup tables
 Verhoeff implementation in Perl (from CPAN)
 Verhoeff implementation in FileMaker Pro
 Verhoeff implementation in MS SQL Server Transact SQL
 Biographical sketch of Jacobus Verhoeff
 Verhoeff validation and generation code in C++
 Verhoeff validation & generation code in Javascript
 Verhoeff validation & generation code in C#, VB.NET, VBA, Java, Python, D, PHP, ActionScript and Pascal/Delphi

Category:合同算術
Category:誤り検出訂正