Unidad 6 · Los códigos BCH · las identidades de Newton resueltas como un sistema lineal: cuántos errores dice el primer determinante no nulo, las fórmulas cerradas hasta t = 3, el caso que las deja en cero sobre cero y lo que cuesta pasar de ahí
Decodificar un código BCH es, en el medio, encontrar el polinomio localizador a partir de los síndromes. El camino más directo lo publicó W. W. Peterson en 1960, y lo refinaron Gorenstein y Zierler: tomar las identidades de Newton como un sistema de ecuaciones lineales y resolverlo. Antes hay que saber de qué orden es el sistema, y eso lo dice un determinante.
Sea un BCH binario de sentido estricto que corrige errores, y supongamos que hubo errores, en las posiciones . Sus números localizadores son , y los síndromes son las sumas de potencias
y el localizador es . Para cada , las identidades de Newton dicen
Tomadas para son ecuaciones lineales en las incógnitas , y los coeficientes son síndromes, que se conocen. Pasando el término sin al otro lado:
La matriz de la izquierda es . Su entrada es : depende sólo de , así que es constante a lo largo de cada antidiagonal. Eso es una matriz de Hankel, y se arma entera con los síndromes. El vector de incógnitas va de a , del índice mayor al menor.
En un código binario, además, la mitad de los síndromes repite a la otra: , porque elevar al cuadrado una suma en característica dos es sumar los cuadrados. En el sistema aparecen , , , pero no aportan nada que , y no tengan.
El sistema pide , que no se conoce. Lo da el determinante:
Teorema 4. Si el patrón de error tiene exactamente componentes no nulas, la matriz es no singular para y singular para todo .
Paso 1: la matriz se factoriza. La entrada de es
que es la entrada de un producto: , con la matriz de cuya columna es y la diagonal de los .
Paso 2: con , el rango no alcanza. tiene columnas, así que su rango es a lo sumo , y el del producto también. Una matriz de con rango menor que tiene determinante nulo.
Paso 3: con , todo es inversible. es cuadrada de Vandermonde, y su determinante es el producto de las diferencias de los nodos, . Las posiciones erradas son distintas y tiene orden , así que los son distintos y no nulos. Queda
El teorema se lee de arriba para abajo: arriba de todas las matrices son singulares, y en la primera que no lo es. Debajo de no promete nada, y no hace falta: el procedimiento nunca llega ahí.
Paso 1. Formar y calcular su determinante. Si no es cero, hubo errores.
Paso 2. Si es cero, bajar a , y así hasta la primera no singular. Su orden es . Si son todas singulares, no hubo errores.
Paso 3. Resolver el sistema de orden y armar . Sus raíces, por la búsqueda de Chien, dan las posiciones.
En la práctica los pasos 1 y 2 son una sola cuenta: la eliminación gaussiana sobre da el determinante como el producto de los pivotes, y si en alguna columna no hay pivote, el determinante es cero y se baja. Si hay, la misma eliminación resuelve el sistema.
El ejemplo 6 del apunte: el (15,5), con , sobre construido con , con errores en las posiciones 3, 5 y 12. Los seis síndromes son
y la primera matriz ya es no singular:
Hubo tres errores. El sistema, con a la derecha, da , y : , el mismo que da el algoritmo iterativo. La primera fila se comprueba a mano, con y :
Con dos errores, ¿cuál de las tres matrices es la primera no singular? ¿Y con cuatro, que es uno más de los que el código corrige?
Arranca con dos errores y sin ningún determinante calculado. Apostá, bajá, y después probá con uno y con tres. Con cuatro errores el teorema ya no vale: probá 0, 1, 2 y 3; después 0, 1, 2 y 4; después 0, 1, 2 y 9. Y con tres errores, poné 0, 5 y 10, y mirá las de abajo.
Con errores en 0, 5 y 10 los síndromes son y . es no singular, con determinante 1, y el procedimiento para ahí con y . Pero y , que no se miran, son singulares las dos: .
Pasa cada vez que , o sea, cuando el tercer localizador es la suma de los otros dos. Recorridos todos los patrones de tres errores, son 35 de 455 en el (15,5) y 155 de 4495 en el (31,16). Por eso el procedimiento baja desde : si subiera desde y se detuviera en la primera singular, en estas ternas concluiría que no hubo ningún error.
Para chico el sistema se resuelve a mano una vez, y lo que queda es una fórmula. La cuenta sale más corta por las identidades de Newton de índice impar que por el sistema de Hankel. Escritas con para , valen para todo :
con el coeficiente reducido módulo dos. Con :
Paso 1: . , así que .
Paso 2: . . Con y : .
Paso 3: . . Con y el del paso 2, los se cancelan y queda .
Para alcanza el paso 2 con . Las tres juntas, como en la ecuación (48) del apunte:
Con el ejemplo 6: , el numerador es cero, así que y . El mismo , sin eliminar nada.
La cantidad está en todas partes, y tiene una lectura limpia. En característica dos, , y entonces
con si hubo dos errores, y si hubo uno. Con tres errores es un producto de diferencias de localizadores distintos, y no se anula. Con dos vale , que tampoco. Y los tres determinantes del procedimiento salen en función de ella:
El teorema 4 de se lee ahí entero. Con dos errores y es singular; con uno se anula , y caen y juntas. Las tres igualdades se comprobaron en cada patrón de hasta tres errores del (15,5) y del (31,16), contra el determinante calculado por eliminación.
Las fórmulas (48) contra la eliminación gaussiana del procedimiento completo, en todos los patrones de hasta errores de cuatro códigos. «Coincide» quiere decir el mismo , coeficiente por coeficiente, una vez quitado el que la fórmula de entrega con dos errores:
| código | fórmula | ν | patrones | coincide | denominador nulo |
|---|---|---|---|---|---|
| (15,5) | t = 3 | 1 | 15 | 0 | 15 |
| (15,5) | t = 3 | 2 | 105 | 105 | 0 |
| (15,5) | t = 3 | 3 | 455 | 455 | 0 |
| (31,16) | t = 3 | 1 | 31 | 0 | 31 |
| (31,16) | t = 3 | 2 | 465 | 465 | 0 |
| (31,16) | t = 3 | 3 | 4495 | 4495 | 0 |
| (15,7) | t = 2 | 1 y 2 | 120 | 120 | 0 |
| (31,21) | t = 2 | 1 y 2 | 496 | 496 | 0 |
En todos los casos el procedimiento completo encontró el verdadero, y la búsqueda de Chien sobre su devolvió exactamente las posiciones puestas. La fórmula de acierta siempre que hubo dos o tres errores, y no da nada en ninguno de los patrones de un error.
Con un error, y : el denominador es cero, y el numerador también. La fórmula de da .
No es una falla de Peterson. La fórmula es la solución del sistema de orden 3, y el procedimiento, con un error, nunca lo resuelve: y son singulares y baja a , que da . Que la fórmula siga sirviendo con dos errores es la excepción: sale cero solo, porque no se anula.
Un circuito que implemente sólo la fórmula tiene que mirar . Si es cero y no, hubo un error y . Si los dos son cero, no hubo errores. La fórmula de no tiene este problema: con un error su numerador es cero pero su denominador no, y da , que es lo correcto.
El teorema 4 supone . Con más, el procedimiento igual encuentra una primera matriz no singular, y resuelve. Recorridos los 1365 patrones de cuatro errores del (15,5):
| cuatro errores | patrones | Peterson dice | Chien | lo que sale |
|---|---|---|---|---|
| declarados | 750 | ν = 3 | menos de 3 raíces | falla |
| mal corregidos | 525 | ν = 3 | 3 raíces | otra palabra, a 7 de la enviada |
| S₁³ + S₃ = 0 | 90 | ν = 1 | 1 raíz | una palabra que no es del código |
En los 1275 de las dos primeras filas Peterson da el mismo que el algoritmo iterativo, y el reparto es el del decodificador: 525 se entregan como otra palabra. Los 90 de la última son los patrones de cuatro errores con : y son singulares, Peterson concluye que hubo un error y , que tiene siempre exactamente una raíz. Las dos comprobaciones de falla —grado de a lo sumo , y tantas raíces como el grado— pasan las dos, y se invierte un bit.
Lo que sale no es una palabra: un patrón de cuatro errores más un bit corregido daría, si lo fuera, una palabra de peso a lo sumo 5, y la distancia mínima es 7. El algoritmo iterativo declara falla en esos 90, porque su sale de grado mayor. En el (31,16) pasa lo mismo con 930 de los 31 465 patrones de cuatro errores. Peterson necesita una comprobación más: que el encontrado reproduzca todos los síndromes, no sólo los que usó. Con es preguntar si , y en los 90, y en los 930, no lo es.
Las fórmulas cerradas se cuentan a mano. Elevar al cuadrado en es lineal sobre los bits —un puñado de XOR—, así que se cuenta aparte. Para : , un cuadrado; , una multiplicación; la inversa de y el producto por ella: dos multiplicaciones, un cuadrado y una inversión. Para : el cuadrado, , , la inversa de , el producto por ella y : cuatro multiplicaciones, un cuadrado y una inversión, sin iteraciones y con latencia fija.
La forma general se midió. Peterson con eliminación gaussiana —una inversión por pivote, sin multiplicar por los ceros ya conocidos, bajando desde —, y el algoritmo iterativo binario, contando cada multiplicación y cada inversión sobre . Cada cifra es el promedio sobre 100 patrones al azar, con el número de errores de la columna, en los BCH de largo 255:
| código | t | (48) | Peterson, ν = t | Peterson, peor ν | iterativo binario |
|---|---|---|---|---|---|
| (255,247) | 1 | 0 · 0 | 1 · 1 | 1 · 1 (ν = 1) | 2 · 1 |
| (255,239) | 2 | 2 · 1 | 6 · 2 | 6 · 2 (ν = 2) | 5 · 2 |
| (255,231) | 3 | 4 · 1 | 17 · 3 | 17 · 4 (ν = 2) | 10 · 3 |
| (255,223) | 4 | — | 36 · 4 | 43 · 6 (ν = 3) | 17 · 4 |
| (255,215) | 5 | — | 65 · 5 | 90 · 9 (ν = 3) | 26 · 5 |
| (255,207) | 6 | — | 105 · 6 | 168 · 12 (ν = 4) | 37 · 6 |
| (255,191) | 8 | — | 231 · 8 | 463 · 20 (ν = 5) | 65 · 8 |
| (255,131) | 16 | — | 1610 · 16 | 6010 · 72 (ν = 9) | 256 · 16 |
Cada celda es «multiplicaciones · inversiones». Tres lecturas.
La forma general pierde enseguida. Ya en la eliminación hace 6 multiplicaciones contra 5 del iterativo binario, y desde ahí la brecha es la de contra : en , 231 contra 65.
El peor caso de Peterson no es . Con menos errores hay que pagar las matrices singulares de arriba: en el (255,191), con cinco errores, , y se eliminan antes de llegar a , y la cuenta sube a 463.
La fórmula cerrada gana mientras existe. En , cuatro multiplicaciones y una inversión contra diez y tres del iterativo, y sin control secuencial.
Sobre dónde se cambia de método. Las curvas de costo asintótico que se suelen comparar son para Peterson, para el algoritmo iterativo general y para el binario. alcanza a en y a en . El cambio que se hace en la práctica, alrededor de , no es el corte de dos de esas curvas: es donde se termina la fórmula cerrada. Hasta se usa (48), que no crece y le gana a todo; desde la fórmula se vuelve inmanejable, y entre la forma general y el iterativo, la tabla ya decidió.
El procedimiento entero sobre , sin librerías: la tabla de potencias de , los síndromes como sumas de potencias, la eliminación que devuelve el determinante y la solución a la vez, y la fórmula de al lado. Lo de los comentarios es la salida de correrlo.
# GF(16) con 1 + X + X⁴: EXP[i] es α^i como entero de 4 bits, LOG lo inverso.
EXP = [1]
for _ in range(14):
x = EXP[-1] << 1
EXP.append(x ^ 0b10011 if x & 0b10000 else x)
LOG = {v: i for i, v in enumerate(EXP)}
def mul(a, b):
return 0 if a == 0 or b == 0 else EXP[(LOG[a] + LOG[b]) % 15]
def inv(a):
return EXP[(15 - LOG[a]) % 15]
def alfa(x):
return '0' if x == 0 else '1' if x == 1 else f'α^{LOG[x]}'
def sindromes(pos, t=3):
"""S_i = Σ X_l^i, con X_l = α^j por cada posición errada j."""
S = []
for i in range(1, 2 * t + 1):
s = 0
for j in pos:
s ^= EXP[i * j % 15]
S.append(s)
return S
def eliminar(A):
"""Gauss sobre GF(16) de la matriz ampliada: devuelve (det, solución)."""
A = [f[:] for f in A]
n, det = len(A), 1
for c in range(n):
p = next((i for i in range(c, n) if A[i][c]), None)
if p is None:
return 0, None # sin pivote: det M = 0
A[c], A[p] = A[p], A[c] # en característica 2, sin signo
det = mul(det, A[c][c])
k = inv(A[c][c])
A[c] = [mul(v, k) for v in A[c]]
for i in range(n):
if i != c and A[i][c]:
f = A[i][c]
A[i] = [v ^ mul(f, w) for v, w in zip(A[i], A[c])]
return det, [f[-1] for f in A]
def peterson(S, t=3):
for mu in range(t, 0, -1):
M = [[S[i + j] for j in range(mu)] + [S[mu + i]] for i in range(mu)]
det, x = eliminar(M)
print(f' det M{mu} = {alfa(det)}')
if det:
return [1] + x[::-1] # x = (σ_µ, …, σ_1)
return [1]
def cerrada_t3(S):
S1, S3, S5 = S[0], S[2], S[4]
D = mul(mul(S1, S1), S1) ^ S3 # S1³ + S3
if D == 0:
return None
s2 = mul(mul(mul(S1, S1), S3) ^ S5, inv(D))
return [1, S1, s2, D ^ mul(S1, s2)]
for pos in [(3, 5, 12), (4, 9), (6,), (0, 5, 10)]:
S = sindromes(pos)
print('errores en', pos, ' S =', ' '.join(alfa(s) for s in S))
sigma = peterson(S)
c = cerrada_t3(S)
print(' Peterson:', ', '.join(alfa(s) for s in sigma),
' (48):', ', '.join(alfa(s) for s in c) if c else 'S1³ + S3 = 0')
# errores en (3, 5, 12) S = 1 1 α^10 1 α^10 α^5
# det M3 = 1
# Peterson: 1, 1, 0, α^5 (48): 1, 1, 0, α^5
# errores en (4, 9) S = α^14 α^13 0 α^11 α^10 0
# det M3 = 0
# det M2 = α^11
# Peterson: 1, α^14, α^13 (48): 1, α^14, α^13, 0
# errores en (6,) S = α^6 α^12 α^3 α^9 1 α^6
# det M3 = 0
# det M2 = 0
# det M1 = α^6
# Peterson: 1, α^6 (48): S1³ + S3 = 0
# errores en (0, 5, 10) S = 0 0 1 0 0 1
# det M3 = 1
# Peterson: 1, 0, 0, 1 (48): 1, 0, 0, 1
Los cuatro casos son los de esta nota: el ejemplo 6, dos errores con en cero, el error único con la fórmula en , y la terna con , donde la fórmula da con sin ningún problema. La línea return [1] + x[::-1] es la del orden de las incógnitas.