序文 §
LFSRの勉強をしていた際に、Berlekamp-Messeyのアルゴリズムが出てきたのでそれ関連でリードソロモン符号について調べてみたら、結構凄さを感じたアルゴリズムだったので紹介します。
問題設定 §
次のような符号化を考える(最初に考案されたリードソロモン符号)。
メッセージ長をm m m 、符号長をn n n とする。なお、許容される符号の誤りはn − m − 1 2 \frac{n - m - 1}2 2 n − m − 1 個までとなる
各バイトやパケットを有限体F p \mathbb F_p F p の要素に変換して、それを係数とするF p \mathbb F_p F p 上のm − 1 m-1 m − 1 次多項式f ( x ) f(x) f ( x ) を作る
長さn n n の符号を次のように生成する
c i = f ( a i ) c_i = f(a_i) c i = f ( a i )
ここでa i a_i a i はi ≠ j i \neq j i = j なら互いに異なるF p \mathbb F_p F p の要素であり、送信者と受信者で共有されている
この符号C = ( f ( a 1 ) , f ( a 2 ) , … , f ( a n ) ) C = (f(a_1), f(a_2), \dots, f(a_n)) C = ( f ( a 1 ) , f ( a 2 ) , … , f ( a n )) に対して誤りが前述のn − m − 1 2 \frac{n-m-1}2 2 n − m − 1 個であればそれを訂正出来るアルゴリズム(Berlekamp-Welch Algorithm)が存在する。以降、この数をk k k とおく(k ≔ n − m − 1 2 k\coloneqq \frac{n-m-1}2 k : = 2 n − m − 1 )
アルゴリズムの大まかな流れはq ( x ) = e ( x ) f ( x ) q(x) = e(x)f(x) q ( x ) = e ( x ) f ( x ) となるような多項式q ( x ) , e ( x ) q(x), e(x) q ( x ) , e ( x ) を求め、q ( x ) e ( x ) \frac{q(x)}{e(x)} e ( x ) q ( x ) を計算してf ( x ) f(x) f ( x ) を求めるという形になる。
アルゴリズム §
input: 受信した(k k k 以下の誤りを含む)符号 ( y 1 , y 2 , … , y n ) (y_1, y_2, \dots, y_n) ( y 1 , y 2 , … , y n )
output: f ( x ) f(x) f ( x )
アルゴリズム本体の前に前節の最後で触れたg ( x ) , e ( x ) g(x), e(x) g ( x ) , e ( x ) に対し、e ( x ) e(x) e ( x ) が何であるかについて示す。これはy i ≠ f ( a i ) y_i \neq f(a_i) y i = f ( a i ) であるようなy i y_i y i を解に持つ多項式であり、次のような形になる。
E ≔ { a i ∣ y i ≠ f ( a i ) } e ( x ) ≔ ∏ i ∈ E ( x − a i )
\begin{aligned}
E &\coloneqq \{a_i \mid y_i \neq f(a_i)\} \cr
e(x) &\coloneqq \prod_{i \in E} (x - a_i)
\end{aligned}
E e ( x ) : = { a i ∣ y i = f ( a i )} : = i ∈ E ∏ ( x − a i )
このe ( x ) e(x) e ( x ) を用いると任意のi i i に対して次が成り立つ。
e ( a i ) f ( a i ) = e ( a i ) y i
e(a_i)f(a_i) = e(a_i)y_i
e ( a i ) f ( a i ) = e ( a i ) y i
誤りがない、つまりy i = f ( a i ) y_i = f(a_i) y i = f ( a i ) の時に成り立つのは自明であり、そうでない場合もe ( a i ) = 0 e(a_i) = 0 e ( a i ) = 0 となることからこの等式が成り立つ。ここで多項式q ( x ) ≔ e ( x ) f ( x ) q(x) \coloneqq e(x)f(x) q ( x ) : = e ( x ) f ( x ) を定義すれば、当然q ( a i ) − e ( a i ) y i = 0 q(a_i) - e(a_i)y_i = 0 q ( a i ) − e ( a i ) y i = 0 が任意のi i i で成り立つ。
ここで、q ( x ) q(x) q ( x ) とe ( x ) e(x) e ( x ) は未知であるが、その係数を変数とした連立方程式を考えるとこれは線形方程式となる。e ( x ) e(x) e ( x ) はその構成からk k k 次のモニック方程式であるので、既知の係数(1)である先頭を除いて、未知の係数は高々k k k 個となる。また、q ( x ) q(x) q ( x ) の次数は定義からk + m k+m k + m 次となるので未知の係数はk + m + 1 k+m+1 k + m + 1 個ある。よって全体で2 k + m + 1 2k+m+1 2 k + m + 1 個の未知変数が存在する線形方程式を解くので、これより多くのa i a_i a i が必要であり、したがって、n ≥ 2 k + m + 1 n \geq 2k+m+1 n ≥ 2 k + m + 1 である。
e ( x ) , q ( x ) e(x), q(x) e ( x ) , q ( x ) について次のように定義する。
e ( x ) ≔ ∑ j = 0 k e j x j q ( x ) ≔ ∑ j = 0 k + m q j x j
\begin{aligned}
e(x) \coloneqq \sum_{j=0}^k e_jx^j\cr
q(x) \coloneqq \sum_{j=0}^{k+m} q_jx^j
\end{aligned}
e ( x ) : = j = 0 ∑ k e j x j q ( x ) : = j = 0 ∑ k + m q j x j
これを用いると任意のi i i に対して次が成り立つ。
q 0 + q 1 a i + q 2 a i 2 + ⋯ + q k + m a i k + m − y i ( e 0 + e 1 a i + e 2 a i 2 + ⋯ + e k − 1 a i k − 1 + a i k ) = 0
q_0 + q_1a_i + q_2a_i^2 + \dots + q_{k+m}a_i^{k+m} - y_i(e_0 + e_1a_i + e_2a_i^2 + \dots + e_{k-1}a_i^{k-1} + a_i^k) = 0
q 0 + q 1 a i + q 2 a i 2 + ⋯ + q k + m a i k + m − y i ( e 0 + e 1 a i + e 2 a i 2 + ⋯ + e k − 1 a i k − 1 + a i k ) = 0
e e e のk k k 次の係数は1であることから、この式には− y i a i k -y_ia_i^k − y i a i k という既知の項が存在する。よってこれを右辺に持っていくことで次の等式が成り立つ。
q 0 + q 1 a i + q 2 a i 2 + ⋯ + q k + m a i k + m − y i ( e 0 + e 1 a i + e 2 a i 2 + ⋯ + e k − 1 a i k − 1 ) = y i a i k
q_0 + q_1a_i + q_2a_i^2 + \dots + q_{k+m}a_i^{k+m} - y_i(e_0 + e_1a_i + e_2a_i^2 + \dots + e_{k-1}a_i^{k-1}) = y_ia_i^k
q 0 + q 1 a i + q 2 a i 2 + ⋯ + q k + m a i k + m − y i ( e 0 + e 1 a i + e 2 a i 2 + ⋯ + e k − 1 a i k − 1 ) = y i a i k
未知数であるe j , q j e_j, q_j e j , q j は線形の項しか存在しないので、全てのi i i に対するこの等式は次のような行列で表すことが出来る。
( 1 a 1 a 1 2 … a 1 k + m − y 1 − y 1 a 1 − y 1 a 1 2 … y 1 a 1 k − 1 1 a 2 a 2 2 … a 2 k + m − y 2 − y 2 a 2 − y 2 a 2 2 … y 2 a 2 k − 1 ⋮ 1 a n a n 2 … a n k + m − y n − y n a n − y n a n 2 … y n a n k − 1 ) ( q 0 q 1 q 2 ⋮ q k + m e 0 e 1 e 2 ⋮ e k − 1 ) = ( y 1 a 1 k y 2 a 2 k ⋮ y n a n k )
\begin{pmatrix}
1 & a_1 & a_1^2 &\dots& a_1^{k+m} & -y_1 & -y_1a_1 & -y_1a_1^2 & \dots & y_1a_1^{k-1} \cr
1 & a_2 & a_2^2 &\dots& a_2^{k+m} & -y_2 & -y_2a_2 & -y_2a_2^2 & \dots & y_2a_2^{k-1} \cr
&&&&&\vdots \cr
1 & a_n & a_n^2 &\dots& a_n^{k+m} & -y_n & -y_na_n & -y_na_n^2 & \dots & y_na_n^{k-1} \cr
\end{pmatrix} \begin{pmatrix}
q_0 \cr q_1 \cr q_2 \cr \vdots \cr q_{k+m} \cr
e_0 \cr e_1 \cr e_2 \cr \vdots \cr e_{k-1}
\end{pmatrix} = \begin{pmatrix}
y_1a_1^k \cr y_2 a_2^k \cr \vdots \cr y_na_n^k
\end{pmatrix}
⎝ ⎛ 1 1 1 a 1 a 2 a n a 1 2 a 2 2 a n 2 … … … a 1 k + m a 2 k + m a n k + m − y 1 − y 2 ⋮ − y n − y 1 a 1 − y 2 a 2 − y n a n − y 1 a 1 2 − y 2 a 2 2 − y n a n 2 … … … y 1 a 1 k − 1 y 2 a 2 k − 1 y n a n k − 1 ⎠ ⎞ ⎝ ⎛ q 0 q 1 q 2 ⋮ q k + m e 0 e 1 e 2 ⋮ e k − 1 ⎠ ⎞ = ⎝ ⎛ y 1 a 1 k y 2 a 2 k ⋮ y n a n k ⎠ ⎞
これが解ければ、e ( x ) e(x) e ( x ) とq ( x ) q(x) q ( x ) が手に入るのでq ( x ) q(x) q ( x ) をe ( x ) e(x) e ( x ) で割って、f ( x ) f(x) f ( x ) が手に入る。
実装(SageMath) §
K = GF ( 521 )
PR .<x> = PolynomialRing (K)
m = 5
coeffs = [K. random_element () for _ in range (m)]
f = PR (coeffs)
k = 3
n = 2 *k+m+ 1
A = [i+ 1 for i in range (n)]
code = [ f (a) for a in A]
for _ in range (k):
i = randint ( 0 , 11 )
code[i] = K. random_element ()
M = []
v = []
for i in range (n):
row_left = [ K (A[i])^e for e in range (k+m+ 1 )]
row_right = [-code[i] * K (A[i])^e for e in range (k)]
row = row_left + row_right
v. append (code[i]* K (A[i])^k)
M. append (row)
M = matrix (K, M)
v = vector (K, v)
polys = M. solve_right (v)
q = PR ( list (polys[:k+m+ 1 ]))
e = PR ( list (polys[k+m+ 1 :]) + [ 1 ])
assert q / e == f
References §