Skip to content

Commit

Permalink
Memoize slow polynomial search functions
Browse files Browse the repository at this point in the history
Fixes #295
  • Loading branch information
mhostetter committed Mar 21, 2022
1 parent 2bd30ef commit f691bb5
Showing 1 changed file with 35 additions and 10 deletions.
45 changes: 35 additions & 10 deletions galois/_fields/_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
irreducible, primitive, and Conway polynomials. They are included here due to a circular dependence with the
Galois field class factory.
"""
import functools
import random
import types
from typing import Sequence, List, Optional, Union, Type
Expand Down Expand Up @@ -550,15 +551,27 @@ def irreducible_poly(
if is_irreducible(poly):
break
else:
elements = range(min_, max_) if method == "min" else range(max_ - 1, min_ - 1, -1)
for element in elements:
poly = Poly.Integer(element, field=field)
if is_irreducible(poly):
break
# The search produces a deterministic result, so we can memoize the output
poly = _irreducible_poly_search(min_, max_, method, field)

return poly


@functools.lru_cache(maxsize=128)
def _irreducible_poly_search(min_, max_, method, field):
"""
Searches for an irreducible polynomial in the range using the specified deterministic method.
"""
elements = range(min_, max_) if method == "min" else range(max_ - 1, min_ - 1, -1)

for element in elements:
poly = Poly.Integer(element, field=field)
if is_irreducible(poly):
return poly

raise RuntimeError(f"No irreducible polynomials exist in {field.name} between {Poly.Integer(min_, field=field)} and {Poly.Integer(max_ - 1, field=field)}.")


@set_module("galois")
def irreducible_polys(order: int, degree: int) -> List[Poly]:
r"""
Expand Down Expand Up @@ -794,15 +807,27 @@ def primitive_poly(order: int, degree: int, method: Literal["min", "max", "rando
if is_primitive(poly):
break
else:
elements = range(min_, max_) if method == "min" else range(max_ - 1, min_ - 1, -1)
for element in elements:
poly = Poly.Integer(element, field=field)
if is_primitive(poly):
break
# The search produces a deterministic result, so we can memoize the output
poly = _primitive_poly_search(min_, max_, method, field)

return poly


@functools.lru_cache(maxsize=128)
def _primitive_poly_search(min_, max_, method, field):
"""
Searches for an primitive polynomial in the range using the specified deterministic method.
"""
elements = range(min_, max_) if method == "min" else range(max_ - 1, min_ - 1, -1)

for element in elements:
poly = Poly.Integer(element, field=field)
if is_primitive(poly):
return poly

raise RuntimeError(f"No primitive polynomials exist in {field.name} between {Poly.Integer(min_, field=field)} and {Poly.Integer(max_ - 1, field=field)}.")


@set_module("galois")
def primitive_polys(order: int, degree: int) -> Poly:
r"""
Expand Down

0 comments on commit f691bb5

Please sign in to comment.