Unidad 6 · Los códigos BCH · las herramientas de GF(2ᵐ): el orden, el cuadrado que es lineal, las raíces que vienen en clases, el polinomio binario que cuesta cada clase, la factorización de X^(2ᵐ−1) + 1 y lo que cuesta cada operación
Un código BCH se especifica por las raíces que sus palabras tienen que anular. Las palabras son binarias; las raíces viven en una extensión, GF(2ᵐ). Para pasar de unas a otras hacen falta cuatro herramientas del cuerpo: el orden de un elemento, que dice qué longitudes se pueden construir; las clases conjugadas, que dicen qué raíces vienen juntas; el polinomio mínimo, que es lo que una clase le cuesta al generador; y el costo de cada operación, que decide cómo se arma el decodificador. Los ejemplos van en GF(2⁴) con , donde : el cuerpo de las potencias de α.
El orden de un elemento no nulo es el menor entero positivo tal que . Todo elemento no nulo cumple , y por eso el orden divide a : si y con , entonces , y como es el menor, . Para una potencia de el orden sale sin recorrer nada:
Los de orden máximo, , son los elementos primitivos. En GF(2⁴), con el orden de cada uno de los quince calculado por potencias sucesivas y contrastado con la fórmula:
| orden | elementos | cuántos |
|---|---|---|
| 1 | 1 | 1 |
| 3 | α⁵, α¹⁰ | 2 |
| 5 | α³, α⁶, α⁹, α¹² | 4 |
| 15 | α, α², α⁴, α⁷, α⁸, α¹¹, α¹³, α¹⁴ | 8 |
Para lo que sigue, el orden importa por una razón: un elemento de orden habilita códigos de longitud . Si tiene orden , es raíz de , y sus potencias son raíces distintas de ese polinomio: todas las que tiene. Las longitudes posibles en GF(2ᵐ) son los divisores de . En GF(2⁶) son 1, 3, 7, 9, 21 y 63, y tiene orden 21: es la raíz de un código de longitud 21 sobre un cuerpo cuyo elemento primitivo tiene orden 63. Contados uno por uno, GF(2⁶) tiene 12 elementos de orden 21 y 36 primitivos. En GF(2⁵) y GF(2⁷), donde 31 y 127 son primos, todo elemento distinto de 1 es primitivo, y la única longitud que no es trivial es la entera.
En un cuerpo de característica dos,
porque . La consecuencia es la que organiza toda la unidad.
Paso 1: un polinomio binario al cuadrado es el mismo polinomio en . Si tiene coeficientes en GF(2), la linealidad del cuadrado da , y como cada es 0 o 1, :
Paso 2: evaluado en una raíz. Si con en GF(2ᵐ), entonces : también es raíz, y por lo mismo , , y así. El cuerpo es finito, así que la sucesión se cierra.
La linealidad también se ve en coordenadas. Si , entonces , y una vez reducidos los cada bit del resultado es una suma fija de bits de la entrada. En GF(2⁴), con y :
Dos XOR, comprobado sobre los dieciséis elementos. Y una caracterización que vuelve en la decodificación: está en GF(2) si y sólo si , porque las únicas soluciones de son 0 y 1.
Los elementos , donde es el menor entero positivo con , forman la clase conjugada de . Por la sección anterior, un polinomio binario que se anula en uno se anula en todos.
Con , elevar al cuadrado es duplicar el exponente módulo , y la clase queda descripta por sus exponentes, la clase ciclotómica de :
En GF(2⁴), módulo 15, los exponentes de van 3, 6, 12, 24 ≡ 9 y 18 ≡ 3: la clase se cierra en cuatro pasos. Las quince potencias se reparten en cinco clases: , , , y .
Tres propiedades, cada una con su porqué.
Las clases particionan los no nulos. Elevar al cuadrado es una biyección: si , entonces y . Una permutación de un conjunto finito se descompone en ciclos disjuntos, y las clases son esos ciclos.
Los conjugados tienen el mismo orden. El orden de divide a , que es impar, así que pide que divida a , y eso es que divida a . En la tabla de la sección 01 cada fila es una unión de clases: la de orden 15 es .
El tamaño de una clase divide a . Todo elemento cumple : a los cuadrados la sucesión volvió seguro, y una sucesión periódica que vuelve en pasos tiene un período que divide a . En GF(2⁴) los tamaños son 1, 4, 4, 2 y 4. En GF(2⁵), con 31 primo, hay siete clases: la de 0 y seis de tamaño 5. En GF(2⁶) hay trece clases: la de 0, una de tamaño 2, dos de 3 y nueve de 6. En GF(2⁸), treinta y cinco: la de 0, una de 2, tres de 4 y treinta de 8.
Una clase corta dice que el elemento vive en un cuerpo más chico. cumple , y los elementos de GF(2⁴) con son exactamente cuatro: . Son un GF(2²) adentro de GF(2⁴), y por eso pedir como raíz va a costar sólo grado 2.
El polinomio mínimo de es el polinomio mónico de menor grado con coeficientes en GF(2) que tiene a por raíz. Cuando se lo escribe , y se obtiene como producto sobre la clase entera:
Los factores tienen coeficientes en GF(2ᵐ); el producto, no. La prueba en tres pasos, con y de 0 a .
Paso 1: al cuadrado, el producto se reordena. Cada factor al cuadrado es . Cuando recorre la clase, también: el último pasa a ser el primero, porque . Entonces .
Paso 2: los coeficientes son sus propios cuadrados. Con , la linealidad da , mientras . Igualando, , y por la caracterización de la sección 02 cada es 0 o 1.
Paso 3: es el de menor grado. Un polinomio binario que se anula en se anula en los conjugados, que son distintos, así que tiene grado . El producto tiene grado , es mónico y es binario: es el mínimo, y su grado es . Además divide a todo polinomio binario que tenga a por raíz: el resto de dividir por es binario, se anula en y tiene grado menor que , así que es cero. Y es irreducible: un factor binario que tuviera a por raíz se llevaría la clase entera.
El producto sobre , factor por factor, en el orden en que los da el cuadrado:
| factor | producto acumulado | fuera de GF(2) |
|---|---|---|
| X + α³ | α³ + X | 1 |
| X + α⁶ | α⁹ + α²X + X² | 2 |
| X + α¹² | α⁶ + α⁴X + α⁷X² + X³ | 3 |
| X + α⁹ | 1 + X + X² + X³ + X⁴ | 0 |
Hasta el último factor los coeficientes son elementos cualesquiera del cuerpo, y con el último caen todos a la vez en GF(2). Los cinco polinomios mínimos de GF(2⁴):
| clase | elementos | orden | polinomio mínimo |
|---|---|---|---|
| C₀ | 1 | 1 | φ₀(X) = 1 + X |
| C₁ | α, α², α⁴, α⁸ | 15 | φ₁(X) = 1 + X + X⁴ |
| C₃ | α³, α⁶, α⁹, α¹² | 5 | φ₃(X) = 1 + X + X² + X³ + X⁴ |
| C₅ | α⁵, α¹⁰ | 3 | φ₅(X) = 1 + X + X² |
| C₇ | α⁷, α¹¹, α¹³, α¹⁴ | 15 | φ₇(X) = 1 + X³ + X⁴ |
es el con que se construyó el cuerpo, como tenía que ser: es su raíz por definición. La tabla no hace falta tenerla a mano: en el círculo de abajo se arma sola, elevando al cuadrado.
Arranca sin nada elegido. Empezá por y mirá cuántos coeficientes quedan fuera de GF(2) en cada paso. Después tocá , que está a dos lugares de distancia en el círculo y tiene un mínimo de grado 2, y , cuya clase se cierra en el primer cuadrado. Si cerrás las cinco clases, el producto deja de tener términos en el medio.
Todo elemento no nulo de GF(2ᵐ) es raíz de , y son raíces distintas para un polinomio de ese grado: no tiene otras. Las clases las particionan, cada clase son las raíces de su mínimo, y dos polinomios mónicos con las mismas raíces simples son el mismo:
con el producto sobre un representante de cada clase. En GF(2⁴),
Multiplicados los mínimos de cada clase, el producto da exacto para de 3 a 8, con 3, 5, 7, 13, 19 y 35 factores. Como los mínimos son irreducibles, ésta es la factorización completa en irreducibles, la que da los códigos cíclicos: cada polinomio generador de longitud 15 es un producto de algunos de estos cinco factores, y hay elecciones, contando las dos triviales.
La tabla también ordena lo que en la Unidad 2 eran tres polinomios sueltos de grado 4. Los tres son irreducibles, porque son mínimos, y no hay otros: un irreducible de grado 4 tiene sus raíces en GF(2⁴), así que es el mínimo de alguna clase de tamaño 4. Dos son primitivos, y , porque sus raíces tienen orden 15. El tercero, , tiene raíces de orden 5: es el con el que el ciclo de α se cerraba en el paso cinco, y el LFSR que reparte los quince estados en tres órbitas de cinco. Su raíz no genera porque el orden de un elemento es el de toda su clase. Y es el recíproco de , con los coeficientes al revés, porque módulo 15: sus raíces son las inversas de las de .
La misma cuenta, más grande: en GF(2⁶) hay nueve mínimos de grado 6 y seis son primitivos; en GF(2⁸), treinta de grado 8 y dieciséis primitivos. Son y : los elementos primitivos, agrupados en clases de .
Todo lo anterior se resume en una restricción: no se puede prescribir una raíz aisladamente. Un polinomio binario que se anula en es múltiplo de , y se anula en toda la clase , se quiera o no. Lo que una raíz le cuesta al generador de un código no es grado 1: es el tamaño de su clase. Pedir son cuatro raíces y trae ocho: las de y las de , con un generador de grado 8. Es el (15,7) de los códigos BCH, y por eso el generador se arma como el mínimo común múltiplo de los mínimos y no como su producto.
El caso que lo muestra es cortar la clase a la mitad. Pedir sólo y da
que tiene esas dos raíces, pero coeficientes fuera de GF(2). No genera un código binario: sus múltiplos no son palabras de ceros y unos. El binario de menor grado con esas raíces es , de grado 4. Y si el elemento del código no es primitivo, las clases se toman sobre sus exponentes, módulo su orden. Con en GF(2⁶), de orden 21, la clase de es módulo 21, y su mínimo, , tiene grado 6.
Construir y decodificar un código BCH gasta casi todo su tiempo en cuatro operaciones del cuerpo, y no cuestan lo mismo.
Suma. En la representación vectorial es un XOR bit a bit: compuertas independientes, sin reducción.
Producto. Hay dos caminos. En potencias, : una suma de enteros, a cambio de dos consultas a una tabla de logaritmos y una de antilogaritmos. En la representación polinómica, el producto de los dos polinomios y la reducción módulo : es la que se lleva a hardware, porque no pide memoria. Si una de las dos entradas es una constante, el producto vuelve a ser una matriz binaria fija.
Cuadrado. Por la sección 02, una matriz binaria fija: XOR sin lógica secuencial, mucho más barato que un producto general.
Inversión. Es la cara. Con tablas, , con dos tablas de entradas. Por Fermat, como , es , y como , se calcula multiplicando los cuadrados sucesivos de : cuadrados y productos. O por el algoritmo de Euclides extendido sobre y .
Contadas las compuertas de cada una, con los del apunte, y , y cada matriz armada fila por fila, comprobada sobre todos los elementos del cuerpo:
| operación | GF(2⁴) | GF(2⁸) |
|---|---|---|
| suma | 4 XOR | 8 XOR |
| cuadrado | 2 XOR | 12 XOR |
| producto por α³ | 3 XOR | — |
| producto general | 16 AND + 15 XOR | 64 AND + 77 XOR |
| inversión por Fermat | 3 cuadrados y 2 productos | 7 cuadrados y 6 productos |
El producto general son AND y XOR para los productos parciales, más los de la reducción: 6 en GF(2⁴) y 28 en GF(2⁸). Una inversión por Fermat en GF(2⁸) son seis productos generales en cadena. Esa diferencia condiciona los algoritmos: el decodificador tiene una versión de Berlekamp-Massey cuyo único propósito es no dividir, y el síndrome par sale de elevar al cuadrado el impar, que es casi gratis. Las dos cosas vuelven en el decodificador en hardware.
Con fec_algebra, la librería del curso. Las clases se arman elevando al cuadrado en el cuerpo, no duplicando exponentes, así que cruzan la tabla de la sección 03 por otro camino; cada mínimo se multiplica factor por factor, imprimiendo el producto acumulado. Lo de abajo es la salida de correrlo.
from fec_algebra import GF, GFPoly
F = GF(m=4, primitive_poly=0b0011) # GF(2⁴), p(X) = 1 + X + X⁴
a = F(2) # α
log = {int(a ** i): i for i in range(15)} # α^i → i
def clase(g):
"""γ, γ², γ⁴, … hasta volver a γ: elevando al cuadrado en el cuerpo."""
c = [g]
while c[-1] * c[-1] != g:
c.append(c[-1] * c[-1])
return c
def texto(p):
"""De X⁰ hacia arriba; un coeficiente que no es 0 ni 1 va como α^i."""
t = []
for k in range(p.degree + 1):
c = int(p[k])
if c:
x = "" if k == 0 else "X" if k == 1 else f"X^{k}"
t.append((x or "1") if c == 1 else f"a^{log[c]}{x}")
return " + ".join(t)
vistos, producto = set(), GFPoly(F, [1])
for i in range(15):
if i in vistos:
continue
phi = GFPoly(F, [1])
for g in clase(a ** i):
phi = phi * GFPoly(F, [F(1), g]) # (·)(X + γ): de mayor a menor grado
vistos.add(log[int(g)])
print(f" · (X + a^{log[int(g)]}) -> {texto(phi)}")
binario = all(int(phi[k]) < 2 for k in range(phi.degree + 1))
print(f"phi_{i}(X) = {texto(phi)} binario: {binario}")
producto = producto * phi
print("producto:", texto(producto))
# · (X + a^0) -> 1 + X
# phi_0(X) = 1 + X binario: True
# · (X + a^1) -> a^1 + X
# · (X + a^2) -> a^3 + a^5X + X^2
# · (X + a^4) -> a^7 + a^1X + a^8X^2 + X^3
# · (X + a^8) -> 1 + X + X^4
# phi_1(X) = 1 + X + X^4 binario: True
# · (X + a^3) -> a^3 + X
# · (X + a^6) -> a^9 + a^2X + X^2
# · (X + a^12) -> a^6 + a^4X + a^7X^2 + X^3
# · (X + a^9) -> 1 + X + X^2 + X^3 + X^4
# phi_3(X) = 1 + X + X^2 + X^3 + X^4 binario: True
# · (X + a^5) -> a^5 + X
# · (X + a^10) -> 1 + X + X^2
# phi_5(X) = 1 + X + X^2 binario: True
# · (X + a^7) -> a^7 + X
# · (X + a^14) -> a^6 + a^1X + X^2
# · (X + a^13) -> a^4 + a^8X + a^12X^2 + X^3
# · (X + a^11) -> 1 + X^3 + X^4
# phi_7(X) = 1 + X^3 + X^4 binario: True
# producto: 1 + X^15
Un detalle muerde. El constructor de GFPoly toma los coeficientes de mayor a menor grado, así que [F(1), g] es ; pero p[k] devuelve el coeficiente de , de menor a mayor. Con el factor escrito [g, F(1)], que es , el programa corre igual, todos los mínimos salen binarios y el producto sigue dando , pero cada sale invertido: da , que es el recíproco. Ninguna de las dos comprobaciones lo ve; lo ve la tabla.