Bitácora · FEC · Concepto

El algoritmo de Berlekamp-Massey

Unidad 6 · Los códigos BCH · el localizador como el registro más corto que genera los síndromes: la discrepancia, la elección de ρ, la versión binaria de t iteraciones, la Tabla 6 fila por fila y la versión sin inversiones

Los síndromes de un código BCH dan un sistema lineal para los coeficientes del polinomio localizador. El método de Peterson lo resuelve con determinantes, y su costo crece como t3. El algoritmo iterativo llega al mismo σ(X) en del orden de t2 operaciones y sin un solo determinante, porque mira el problema de otra manera: busca el registro de desplazamiento más corto que genera los síndromes. E. R. Berlekamp lo presentó en 1965 para los BCH binarios, y J. L. Massey lo leyó como síntesis de registros en 1969.

01 · El localizador es un registro

Sea un código BCH binario de sentido estricto que corrige t errores, con síndromes S1,…,S2t. Si hubo ν≤t errores con números localizadores X1,…,Xν, el localizador es

σ(X)=∏l=1ν(1+XlX)=1+σ1X+⋯+σνXν

y las identidades de Newton, para i>ν, se escriben como una recurrencia:

Si=σ1Si−1+σ2Si−2+⋯+σνSi−ν

Cada síndrome es una combinación de los ν anteriores, con coeficientes fijos. Es lo que hace un LFSR de ν etapas con polinomio de conexión σ(X): cargado con S1,…,Sν, saca el resto de la sucesión. La única diferencia con los de la Unidad 5 es que las etapas guardan elementos de GF(2m), no bits.

Encontrar σ(X) pasa a ser un problema de síntesis: el registro más corto que genera S1,…,S2t. Más corto, porque el patrón más probable es el de menos errores, y el grado de σ(X) es el número de errores. El algoritmo lo arma de a una identidad por vez: arranca con un registro que genera el primer síndrome y, en cada paso, lo corrige lo mínimo indispensable para que genere también el siguiente.

02 · La discrepancia y la elección de ρ

El algoritmo produce una sucesión de polinomios σ(μ)(X), cada uno el de menor grado que satisface las primeras μ identidades. Su grado es lμ. Para pasar al siguiente se mide cuánto falla σ(μ) en la identidad número μ+1. Esa medida es la discrepancia:

dμ=Sμ+1+σ1(μ)Sμ+⋯+σlμ(μ)Sμ+1−lμ

Es lo que el registro predice para Sμ+1, sumado a lo que vale. Si dμ=0, el registro acierta y pasa igual: σ(μ+1)=σ(μ), lμ+1=lμ. Si no, se busca un paso anterior ρ con dρ≠0 y ρ−lρ lo más grande posible, y se corrige con él:

σ(μ+1)(X)=σ(μ)(X)+dμdρ−1Xμ−ρσ(ρ)(X)

y el grado pasa a ser

lμ+1=max(lμ,lρ+μ−ρ)

Por qué el término agregado arregla la identidad μ+1 sin romper las anteriores:

Paso 1: correr es atrasar la identidad. Multiplicar σ(ρ) por Xμ−ρ corre sus coeficientes μ−ρ lugares. Lo que el polinomio corrido aporta a la identidad j es lo que σ(ρ) aportaba a la identidad j−(μ−ρ).

Paso 2: en las identidades viejas aporta cero. Para j≤μ, la identidad atrasada tiene número ≤ρ, y σ(ρ) las cumplía todas. Lo que σ(μ) ya acertaba, lo sigue acertando.

Paso 3: en la nueva aporta exactamente la discrepancia. Para j=μ+1, la identidad atrasada es la ρ+1, donde σ(ρ) fallaba por dρ. Escalado por dμdρ−1, aporta dμ, que se cancela con la discrepancia de σ(μ). En característica dos, sumar es restar.

Cualquier ρ con dρ≠0 arregla la identidad. La elección decide el grado: lρ+μ−ρ es más chico cuanto más grande es ρ−lρ. Massey probó que con esa elección el registro es, en cada paso, el más corto posible: su largo cumple lμ+1=max(lμ,μ+1−lμ), y no hay registro más corto que genere esos μ+1 términos. Al cabo de 2t pasos, si hubo a lo sumo t errores, σ(2t)(X) es el localizador.

El cálculo se ordena en una tabla con una fila por paso: μ, σ(μ), dμ, lμ y μ−lμ, la columna que sirve para elegir ρ. Las dos primeras filas no son iteraciones, son el arranque: μ=−1 con σ(−1)=1 y d−1=1, que existe para que el primer paso tenga un ρ del cual tirar; y μ=0 con σ(0)=1 y d0=S1.

03 · En binario, la mitad de los pasos no hace nada

En un código binario los síndromes pares son cuadrados: S2i=Si2. Con eso se prueba que, si σ(μ) cumple las identidades hasta un orden μ par, cumple también la siguiente: la discrepancia de todo paso de índice impar es cero, y ese paso copia la fila. Se ve en la forma general aplicada al (15,5) con errores en las posiciones 3, 5 y 12:

μσ(X)dμlμμ − lμρ
−1110−1—
01100—
11 + X010−1
21 + Xα⁵11—
31 + X + α⁵X²0210
41 + X + α⁵X²α¹⁰22—
51 + X + α⁵X³0322
61 + X + α⁵X³—33—

La columna ρ dice con qué fila se armó cada polinomio. Las filas 1, 3 y 5 tienen discrepancia nula, y no es suerte de este patrón: con la forma general corrida sobre los 575 patrones de uno, dos y tres errores del (15,5), las discrepancias de índice impar dieron cero en todos, y el σ(X) final fue el mismo que el de la versión binaria.

La versión binaria recorre sólo los pasos pares. Se los reindexa con μ=−12,0,1,…,t, y el algoritmo termina en t iteraciones en lugar de 2t. Cambian dos cosas. La discrepancia se calcula contra los síndromes impares:

dμ=S2μ+1+σ1(μ)S2μ+⋯+σlμ(μ)S2μ+1−lμ

Y la corrección se corre el doble, con ρ elegido por el mayor 2ρ−lρ:

σ(μ+1)(X)=σ(μ)(X)+dμdρ−1X2(μ−ρ)σ(ρ)(X)

El arranque es μ=−12, con σ=1, d=1, l=0, y μ=0, con σ=1 y d0=S1. El medio del primero es para que el corrimiento 2(μ−ρ) desde él dé un número impar: es la fila −1 de la forma general, contada en pasos dobles. La simplificación vale sólo para códigos binarios. Para uno con símbolos en GF(2m), como un Reed-Solomon, S2i=Si2 deja de valer y hay que dar los 2t pasos.

04 · La Tabla 6, fila por fila

El (15,5) corrige t=3 errores sobre GF(24), con 1+X+X4. Se transmite la palabra nula y llega r(X)=X3+X5+X12. Los seis síndromes son

S1=1,S2=1,S3=α10,S4=1,S5=α10,S6=α5

con los pares como cuadrados de los impares: S6=(α10)2=α20=α5. El algoritmo binario da tres iteraciones:

Fila 0. d0=S1=1. El único paso previo con discrepancia no nula es ρ=−12, y el corrimiento es 2(0+12)=1: σ(1)=1+X, de grado 1.

Fila 1. d1=S3+σ1S2=α10+1=α5. Los candidatos son ρ=−12, con 2ρ−lρ=−1, y ρ=0, con 0. Gana el segundo, corrimiento 2: σ(2)=1+X+α5X2.

Fila 2. d2=S5+σ1S4+σ2S3=α10+1+α5α10=α10, porque α15=1 cancela el 1. Ahora gana ρ=1, con 2ρ−lρ=1; el factor es α10/α5=α5 y el corrimiento 2:

σ(3)(X)=(1+X+α5X2)+α5X2(1+X)=1+X+α5X3
μσ(X)dμlμ2μ − lμρ
−½110−1—
01100—
11 + Xα⁵11−½
21 + X + α⁵X²α¹⁰220
31 + X + α⁵X³—331

Son las filas pares de la tabla de la forma general, renumeradas. El grado final, 3, es el número de errores. Las raíces de 1+X+α5X3 son α3, α10 y α12; sus inversos, α12, α5 y α3, son los localizadores, y dan las posiciones 12, 5 y 3. Encontrarlas es la búsqueda de Chien. Peterson, con su fórmula cerrada para t=3, da el mismo polinomio; y comparados en los 575 patrones de hasta tres errores del (15,5), los dos coinciden siempre.

Antes de usar el widget, pensá la fila 1 de otra manera: ¿qué pasa si ahí se elige ρ=−12, el candidato que pierde? ¿Y si el que se elige mal es el de la fila 2?

Algoritmo La tabla del algoritmo binario en el (15,5), fila por fila — tocá las posiciones para poner o sacar errores; se transmite la palabra nula. En cada fila con discrepancia no nula elegís vos la fila ρ con la que se corrige, y la tabla aplica tu elección.
Errores · posición 0 a la izquierda

μσ(X)dμlμ2μ − lμρ
errores puestos — grado de σ — raíces dan —

Arranca con el patrón de la Tabla 6 y sólo las dos filas del arranque. Hacela entera eligiendo vos. Después volvé a empezar y, en la fila 2, elegí ρ=0; y otra vez con ρ=−12 en la fila 1. Probá con dos errores, en las posiciones 4 y 9, y con cuatro. Al final, prendé «sin inversiones» y mirá qué cambia y qué no.

05 · Lo que dice cada columna

lμ es el largo del registro, y sólo crece. Al terminar es el grado de σ(X), y el decodificador lo lee como el número de errores. La columna 2μ−lμ está para elegir ρ de un vistazo: entre las filas con dμ≠0, la del número más grande.

Con menos errores que t, las últimas discrepancias son cero. Con errores en 4 y 9, d0=α14, d1=α12 y d2=0: la última iteración copia 1+α14X+α13X2, de grado 2. Un circuito de latencia fija la hace igual.

Elegir mal ρ no siempre se nota, y por eso el criterio importa. Sobre el patrón de la Tabla 6:

elecciónσ(X) finalgradoraíces dan
la del algoritmo1 + X + α⁵X³33, 5, 12
ρ = −½ en la fila 11 + X + α⁵X³33, 5, 12
ρ = 0 en la fila 21 + X + α⁵X² + α¹⁰X⁴4ninguna
ρ = −½ en la fila 21 + X + α⁵X² + α¹⁰X⁵53, 5, 10, 12

El primer desvío llega bien por casualidad. Con ρ=−12 en la fila 1 el corrimiento es 3, y sale σ(2)=1+X+α5X3: genera los primeros cuatro síndromes, pero con l2=3 donde alcanzaba 2. Ese registro de más resultó ser el localizador, y d2=0. En la fila 2 ya no hay margen: un registro más largo que el necesario es un σ(X) que no es el localizador, y el decodificador o declara falla o, con el de grado 5, encuentra una raíz que no es un error.

06 · La versión sin inversiones

La corrección lleva el factor dμdρ−1: una inversión en GF(2m) en cada iteración con discrepancia no nula, dentro del lazo. En hardware la inversión es la operación lenta, y queda en el camino crítico. La salida es que a σ(X) se lo puede multiplicar por cualquier constante no nula sin que cambien sus raíces. Multiplicando la actualización por dρ:

σ(μ+1)(X)=dρσ(μ)(X)+dμX2(μ−ρ)σ(ρ)(X)

Sólo productos. Esta versión, de H. O. Burton en 1971, cambia la inversión y el producto del factor por un producto más en cada coeficiente de σ(μ): todos los coeficientes hacen la misma cuenta, y por eso se arma como una fila de celdas iguales.

Que todo siga cerrando tiene un paso no evidente: las filas guardadas también quedan escaladas, cada una por su propio factor, y la discrepancia, que es lineal en σ, se escala con el mismo factor que su fila. Si la fila μ tiene factor cμ y la ρ tiene cρ, la cuenta sin inversiones da

cρdρ·cμσ(μ)+cμdμ·X2(μ−ρ)cρσ(ρ)=cμcρdρσ(μ+1)

el polinomio con inversiones por un factor no nulo. En la Tabla 6 las dos primeras correcciones salen con dρ=1 y no cambian nada; la tercera usa d1=α5:

σ(3)(X)=α5+α5X+α10X3=α5(1+X+α5X3)

En el ejemplo integral, el de la Tabla 8, el factor se acumula antes: la discrepancia de la fila 2 sale α8 en lugar de α7, porque la fila ya venía multiplicada por α, y el polinomio final es α2 veces el de la tabla. Comparadas las dos versiones en los 575 patrones de uno, dos y tres errores del (15,5), el polinomio sin inversiones fue el otro por una constante no nula en todos, con las mismas raíces. Lo mismo en los 120 patrones del (15,7), los 496 del (31,21) y los 4991 del (31,16).

07 · Con más de t errores

El teorema de Massey promete el registro más corto, no el localizador. Con más de t errores, el registro más corto que genera los 2t síndromes suele ser otro, y el algoritmo lo entrega igual, sin aviso. Lo que queda es mirar el resultado: el decodificador declara falla si el grado pasa de t, o si Chien no encuentra tantas raíces distintas como el grado. En los 1365 patrones de cuatro errores del (15,5):

grado de σraícespatroneslo que pasa
41 o 490falla, por el grado
30750falla, por las raíces
33525corrige a otra palabra

Los 840 declarados y los 525 entregados en silencio son el mismo reparto que da cualquier decodificación incompleta de este código: los 525 son los patrones a distancia 3 de alguna de las 15 palabras de peso 7, y para ellos el registro más corto es un localizador legítimo, el de esa otra palabra. Entre los 90 de grado 4 hay 15 en que las cuatro raíces son justo las cuatro posiciones erradas, y el decodificador falla igual: con seis síndromes no hay garantía de que un registro de cuatro etapas sea el bueno, y no lo usa.

08 · La cuenta en Python

El algoritmo binario sobre GF(24) con tablas de exponentes y logaritmos, en sus dos versiones: la única diferencia está en los dos coeficientes a y b de la actualización. Corre la Tabla 6 y después compara las dos versiones en los 575 patrones. Lo de los comentarios es la salida de correrlo.

from itertools import combinations

# GF(2^4) con 1 + X + X^4: EXP[i] es α^i como entero de 4 bits.
EXP, LOG = [1] * 30, {}
for i in range(1, 30):
    x = EXP[i - 1] << 1
    EXP[i] = x ^ 0b10011 if x & 0b10000 else x
for i in range(15):
    LOG[EXP[i]] = i

def mul(a, b):
    return 0 if a == 0 or b == 0 else EXP[LOG[a] + LOG[b]]

def inv(a):
    return EXP[(15 - LOG[a]) % 15]

def alfa(x):
    return '0' if x == 0 else '1' if x == 1 else 'α' if x == 2 else f'α^{LOG[x]}'

def sindromes(posiciones, t=3):
    S = [0] * (2 * t + 1)                  # S[i] es S_i; S[0] no se usa
    for i in range(1, 2 * t + 1):
        for j in posiciones:
            S[i] ^= EXP[(i * j) % 15]
    return S

def berlekamp(S, t=3, sin_inversiones=False):
    """La versión binaria: filas (μ, σ, d, l), con μ = -1/2 como -0.5."""
    filas = [(-0.5, [1], 1, 0)]
    sigma, l = [1], 0
    for mu in range(t + 1):
        d = None
        if mu < t:                         # d_μ = Σ σ_i S_{2μ+1-i}, con σ_0 incluido
            d = 0
            for i, c in enumerate(sigma[:2 * mu + 1]):
                d ^= mul(c, S[2 * mu + 1 - i])
        filas.append((mu, sigma, d, l))
        if not d:
            continue
        rho = max((f for f in filas[:-1] if f[2]), key=lambda f: 2 * f[0] - f[3])
        k = int(2 * (mu - rho[0]))         # el corrimiento 2(μ - ρ)
        if sin_inversiones:
            a, b = rho[2], d               # σ' = d_ρ σ + d_μ X^k σ^(ρ)
        else:
            a, b = 1, mul(d, inv(rho[2]))  # σ' = σ + d_μ d_ρ⁻¹ X^k σ^(ρ)
        nuevo = [mul(a, c) for c in sigma] + [0] * (len(rho[1]) + k)
        for i, c in enumerate(rho[1]):
            nuevo[i + k] ^= mul(b, c)
        while nuevo[-1] == 0:
            nuevo.pop()
        sigma, l = nuevo, max(l, rho[3] + k)
    return filas

S = sindromes([3, 5, 12])
print('S =', ', '.join(alfa(s) for s in S[1:]))
for nombre, si in (('con inversiones', False), ('sin inversiones', True)):
    print(nombre)
    for mu, sigma, d, l in berlekamp(S, sin_inversiones=si):
        print(f'  {mu:>4}  σ = {" ".join(alfa(c) for c in sigma):<14} d = {alfa(d) if d is not None else "—":<4} l = {l}')

# Todos los patrones de 1, 2 y 3 errores: ¿el σ sin inversiones es c·σ?
distintos = 0
total = 0
for w in (1, 2, 3):
    for pos in combinations(range(15), w):
        S = sindromes(pos)
        s1 = berlekamp(S)[-1][1]
        s2 = berlekamp(S, sin_inversiones=True)[-1][1]
        c = s2[0]
        total += 1
        distintos += [mul(x, inv(c)) for x in s2] != s1
print(total, 'patrones,', distintos, 'distintos')
# S = 1, 1, α^10, 1, α^10, α^5
# con inversiones
#   -0.5  σ = 1              d = 1    l = 0
#      0  σ = 1              d = 1    l = 0
#      1  σ = 1 1            d = α^5  l = 1
#      2  σ = 1 1 α^5        d = α^10 l = 2
#      3  σ = 1 1 0 α^5      d = —    l = 3
# sin inversiones
#   -0.5  σ = 1              d = 1    l = 0
#      0  σ = 1              d = 1    l = 0
#      1  σ = 1 1            d = α^5  l = 1
#      2  σ = 1 1 α^5        d = α^10 l = 2
#      3  σ = α^5 α^5 0 α^10 d = —    l = 3
# 575 patrones, 0 distintos

Los coeficientes van del grado 0 para arriba: 1 1 0 α^5 es 1+X+α5X3. La discrepancia se calcula con σ0 adentro de la suma, que con inversiones vale 1 y sin inversiones no: así la misma línea sirve para las dos. Y la comparación del final divide por σ0 sólo para comparar; el decodificador no lo necesita.

Para tener a mano

  1. σ(X) es el polinomio de conexión del registro más corto que genera S1,…,S2t. Su grado es el número de errores.
  2. Discrepancia: lo que falla el registro actual en la identidad siguiente. Si es cero, la fila se copia.
  3. Si no, se corrige con la fila ρ de dρ≠0 y mayor ρ−lρ: σ(μ+1)=σ(μ)+dμdρ−1Xμ−ρσ(ρ), y lμ+1=max(lμ,lρ+μ−ρ).
  4. El término agregado no toca las identidades viejas y cancela la nueva. El criterio de ρ es lo que hace al registro el más corto.
  5. Binario: como S2i=Si2, los pasos impares tienen d=0. Quedan t iteraciones, μ=−12,0,…,t, con corrimiento 2(μ−ρ) y criterio 2ρ−lρ.
  6. Tabla 6, errores en 3, 5 y 12: d0=1, d1=α5, d2=α10; ρ=−12,0,1; σ=1+X+α5X3.
  7. Sin inversiones: σ(μ+1)=dρσ(μ)+dμX2(μ−ρ)σ(ρ). El mismo σ por una constante, las mismas raíces; σ0≠1 y las discrepancias también escaladas.
  8. Con más de t errores entrega el registro más corto, que no es el localizador: con cuatro en el (15,5), 840 fallas declaradas y 525 palabras equivocadas.
← Anterior Siguiente → Inicio
Relacionados Los síndromes y el polinomio localizador El método de Peterson La búsqueda de Chien El decodificador BCH en hardware El LFSR y las m-secuencias El (15,5) de punta a punta