Source code for galois.factory

import numpy as np

from . import gfp
from .algorithm import is_prime, primitive_root, min_poly
from .gf import DTYPES
from .gf2 import GF2
from .poly import Poly


[docs]def GF_factory(p, m, prim_poly=None, rebuild=False): # pylint: disable=redefined-outer-name """ Factory function to construct Galois field array classes of type GF(p^m). If `p = 2` and `m = 1`, this function will return `galois.GF2`. If `p = 2` and `m > 1`, this function will invoke `galois.GF2m_factory()`. If `p is prime` and `m = 1`, this function will invoke `galois.GFp_factory()`. If `p is prime` and `m > 1`, this function will invoke `galois.GFpm_factory()`. Parameters ---------- p : int The prime characteristic of the field GF(p^m). m : int The degree of the prime characteristic of the field GF(p^m). prim_poly : galois.Poly, optional The primitive polynomial of the field. Default is `None` which will auto-determine the primitive polynomial. rebuild : bool, optional A flag to force a rebuild of the class and its lookup tables. Default is `False` which will return the cached, previously-built class if it exists. Returns ------- galois.GF2Base or galois.GFpBase A new Galois field class that is a sublcass of `galois.GFBase`. """ if not isinstance(p, int): raise TypeError(f"Galois field prime characteristic `p` must be an integer, not {type(p)}") if not isinstance(m, int): raise TypeError(f"Galois field characteristic degree `m` must be an integer, not {type(m)}") if not (prim_poly is None or isinstance(prim_poly, Poly)): raise TypeError(f"Primitive polynomial `prim_poly` must be either None or galois.Poly, not {type(prim_poly)}") if not isinstance(rebuild, bool): raise TypeError(f"Rebuild Galois field class flag `rebuild` must be a bool, not {type(rebuild)}") if not is_prime(p): raise ValueError(f"Galois field prime characteristic `p` must be prime, not {p}") if not m >= 1: raise ValueError(f"Galois field characteristic degree `m` must be >= 1, not {m}") if p == 2 and m == 1: if not (prim_poly is None or prim_poly is GF2.prim_poly): raise ValueError(f"In GF(2), the primitive polynomial `prim_poly` must be either None or {GF2.prim_poly}, not {prim_poly}") cls = GF2 # elif p == 2: # cls = GF2m_factory(m, rebuild=rebuild) else: cls = GFp_factory(p, rebuild=rebuild) return cls
[docs]def GFp_factory(p, rebuild=False): """ Factory function to construct Galois field array classes of type GF(p). Parameters ---------- p : int The prime characteristic of the field GF(p). rebuild : bool, optional A flag to force a rebuild of the class and its lookup tables. Default is `False` which will return the cached, previously-built class if it exists. Returns ------- galois.GFpBase A new Galois field class that is a sublcass of `galois.GFpBase`. """ # If the requested field has already been constructed, return it instead of rebuilding key = (p,) if not rebuild and key in GFp_factory.classes: return GFp_factory.classes[key] if not is_prime(p): return ValueError(f"GF(p) fields must have a prime characteristic `p`, not {p}") if not 2 <= p <= 2**16: return ValueError(f"GF(p) classes are only supported for 2 <= p <= 2**16, not {p}") order = p name = "GF{}".format(order) dtypes = [dtype for dtype in DTYPES if np.iinfo(dtype).max >= order] # Use the smallest primitive root as the multiplicative generator for the field alpha = primitive_root(p) # Create new class type cls = type(name, (gfp.GFpBase,), { "characteristic": p, "power": 1, "order": p, "alpha": alpha, "dtypes": dtypes }) # Construct the field-specific lookup tables cls._build_luts() # pylint: disable=protected-access # JIT compile the numba ufuncs cls.target("cpu") # Assign the primitive polynomial with coefficients in the field cls.prim_poly = min_poly(cls.alpha, cls, 1) # Add class to dictionary of flyweights GFp_factory.classes[p] = cls return cls
GFp_factory.classes = {}