from irreduc_types import IRREDUCIBLE, UNKNOWN class MurtyCriterion: def __init__(self, max_p=None): self.name = "Murty's irreducibility criterion" self.max_p = max_p def name(self): return self.name def check(self, f): # http://cms.dm.uba.ar/academico/materias/2docuat2011/teoria_de_numeros/Irreducible.pdf # Theorem 1 h = 0 for exp, coeff in poly_non_zero_exps(f): if exp != f.degree(): h = max(h, abs(coeff / f.LC())) nmin = int(math.ceil(h + 2)) for n in range(nmin, nmin + 5): val = f.eval(n) if sympy.isprime(val) and (not self.max_p or val < self.max_p): return IRREDUCIBLE, {'n': n, 'p': val} return UNKNOWN, None if __name__ == '__main__': poly = create_polynomial(sys.argv[1]) check_common(poly, sys.argv[1], MurtyCriterion())
# check if there are roots inside as well as outside of unit circle try: all = mpmath.polyroots(f.all_coeffs(), maxsteps=100) inside_unit_circle = 0 outside_unit_circle = 0 on_unit_circle = 0 for root in all: root_size = abs(root) if root_size == 1: on_unit_circle += 1 elif root_size < 1: inside_unit_circle += 1 else: outside_unit_circle += 1 if on_unit_circle == 0: return IRREDUCIBLE, {'s': const_coeff, "on": on_unit_circle} except mpmath.libmp.libhyper.NoConvergence: # could not get complex roots, too bad pass return UNKNOWN, None if __name__ == '__main__': poly = create_polynomial(sys.argv[1]) check_common(poly, sys.argv[1], OsadaCriterion()) check_common(poly, sys.argv[1], OsadaCriterionNonSharp())
if power == 1: # good candidate, it must not divide leading term lead_coeff = f.LC() if lead_coeff % p == 0: # bad luck continue # it must divide or other terms for exp, coeff in poly_non_zero_exps(f): if exp != f.degree(): if coeff % p != 0: # bad luck... return UNKNOWN, None # finally the polynomial must not have rational roots numerators = sympy.ntheory.factorint(const_coeff) denominators = sympy.ntheory.factorint(lead_coeff) for num in numerators: for denom in denominators: for sign in (-1, 1): if f.eval(sympy.Rational(sign * num, denom)) == 0: # rational root... return UNKNOWN, None return IRREDUCIBLE, {"p": p} return UNKNOWN, None if __name__ == '__main__': poly = create_polynomial(sys.argv[1]) check_common(poly, sys.argv[1], EisensteinCriterionV2())
def __init__(self): self.name = "Schur's irreducibility criterion" def name(self): return self.name def check(self, f): # http://www.math.uconn.edu/~kconrad/blurbs/gradnumthy/schurtheorem.pdf # Theorem 1, multiplied to get Z[x] n = f.degree() lead_coeff = f.LC() if abs(lead_coeff) != 1: return UNKNOWN, None fact = n for exp in reversed(range(1, n)): coeff = get_coeff(f, exp) if coeff % fact != 0: return UNKNOWN, None fact *= exp # fact now contains n! const_coeff = f.TC() if const_coeff != fact: return UNKNOWN, None return IRREDUCIBLE, None if __name__ == '__main__': poly = create_polynomial(sys.argv[1]) check_common(poly, sys.argv[1], SchurCriterion())
def __init__(self): self.name = "Perron's (non-sharp) irreducibility criterion" def name(self): return self.name def check(self, f): const_coeff = f.TC() if const_coeff == 0: return REDUCIBLE, None lead_coeff = f.LC() if lead_coeff != 1: return UNKNOWN, None a_nm1 = abs(get_coeff(f, f.degree() - 1)) s = 1 for exp, coeff in poly_non_zero_exps(f): if exp < f.degree() - 1: s += abs(coeff) if a_nm1 == s: f1 = f.subs(VAR_X, 1) f2 = f.subs(VAR_X, -1) if f1 != 0 and f2 != 0: return IRREDUCIBLE, None return UNKNOWN, None if __name__ == '__main__': poly = create_polynomial(sys.argv[1]) check_common(poly, sys.argv[1], PerronCriterion()) check_common(poly, sys.argv[1], PerronNonSharpCriterion())
OsadaCriterion(max_p=max_p), OsadaCriterionNonSharp(max_p=max_p), PolyaCriterion(), LevitCriterion(), SchurCriterion(), BonciocatCriterion(), GaloisFieldsCriterion(), ComplexRootsCriterion2(), ComplexRootsCriterion(max_p=max_p), ComplexRootsCriterion3(max_p=max_p), ] tryWithSubs = [] for criterion in criteria: poly=polys[0] if not check_common(poly[0], sub_name(poly[1], poly[2], poly[3]), criterion): tryWithSubs.append(criterion) print('') print('Trying failed criteria with substitutions') if subs: for criterion in tryWithSubs: # original poly does not satisfy this criterion directly, now try substitutions #print("No result for '%s', trying substitutions" % criterion.name) for poly in polys: check_common(poly[0], sub_name(poly[1], poly[2], poly[3]), criterion) if isinstance(criterion, GaloisFieldsCriterion): # dirty hack break
from irreduc_utils import create_polynomial, poly_all_exps, check_common from irreduc_types import IRREDUCIBLE, UNKNOWN class BrauerCriterion: def __init__(self): self.name = "Brauer's irreducibility criterion" def name(self): return self.name def check(self, f): # Polynomials - Prasolov - Theorem 2.2.6 ([Br]) last = 0 lead_coeff = f.LC() if abs(lead_coeff) != 1: return UNKNOWN, None for exp, coeff in poly_all_exps(f): if exp != f.degree(): coeff = -coeff coeff *= lead_coeff # in case the original differs by multiple of -1 if coeff < last or coeff <= 0: return UNKNOWN, None last = coeff return IRREDUCIBLE, {"sign": lead_coeff} if __name__ == '__main__': poly = create_polynomial(sys.argv[1]) check_common(poly, sys.argv[1], BrauerCriterion())
for n in range(0, m + 1): for s in S: new = s + n * xs[l - 1] if new > 0 and (2 * new <= f.degree()): tmp.add(new) S = S.union(tmp) S.remove(0) # we are interested only in those sets that are not just full set of {1,2,...,n/2} if S != trivial: Sps['S%i' % prime] = S if not Sps: return UNKNOWN, None # final part, intersection... inter = set.intersection(*list(Sps.values())) if len(inter) > 0: return UNKNOWN, None # we have succeeded! return IRREDUCIBLE, Sps if __name__ == '__main__': poly = create_polynomial(sys.argv[1]) check_common(poly, sys.argv[1], BonciocatCriterion())
# all possible degrees of irreducible factors in Z[x] sums = {} trivial = set(range(1, f.degree() + 1)) for p in irreduc_factors_degrees: sums_p = subsets_sums(irreduc_factors_degrees[p]) if sums_p != trivial: sums[p] = sums_p if not sums: return UNKNOWN, None # then if intersection of these is empty or {deg(f)}, then lesser degree factor is impossible # thus polynomial will have to be irreducible inter = set.intersection(*list(sums.values())) if f.degree() in inter: inter.remove(f.degree()) if not inter: # intersection is empty, imcompatible factors! res["degrees"] = sums if res: return IRREDUCIBLE, res return UNKNOWN, None if __name__ == '__main__': poly = create_polynomial(sys.argv[1]) check_common(poly, sys.argv[1], GaloisFieldsCriterion())
inside_unit_circle = 0 outside_unit_circle = 0 on_unit_circle = 0 for root in all: root_size = abs(root) if root_size == 1: on_unit_circle += 1 elif root_size < 1: inside_unit_circle += 1 else: outside_unit_circle += 1 if (inside_unit_circle + on_unit_circle == 0): return IRREDUCIBLE, { "inside/on": inside_unit_circle + on_unit_circle, "outside": outside_unit_circle, "p": p } except Exception as e: # could not get complex roots, too bad pass return UNKNOWN, None if __name__ == '__main__': poly = create_polynomial(sys.argv[1]) check_common(poly, sys.argv[1], ComplexRootsCriterion()) check_common(poly, sys.argv[1], ComplexRootsCriterion2()) check_common(poly, sys.argv[1], ComplexRootsCriterion3())
class PolyaCriterion: def __init__(self): self.name = "Polya's irreducibility criterion" def name(self): return self.name def check(self, f): # Polynomials by Prasolov, Theorem 2.2.8 (Polya) n = f.degree() m = (n + 1) // 2 suitable = [] rhs = sympy.factorial(m) / (2 ** m) for a in range(-20, 20 + 1): val = abs(f.eval(a)) if val == 0: # clearly this is reducible... return REDUCIBLE, None if val < rhs: suitable.append(a) if len(suitable) >= n: return IRREDUCIBLE, {'a': suitable} return UNKNOWN, None if __name__ == '__main__': poly = create_polynomial(sys.argv[1]) check_common(poly, sys.argv[1], PolyaCriterion())
class CohnCriterion: def __init__(self, max_p=None): self.name = "Cohn's irreducibility criterion" self.max_p = max_p def name(self): return self.name def check(self, f): # first we need to ensure coefficients are non-negative max_coeff = 0 for exp, coeff in poly_non_zero_exps(f): if coeff < 0: return UNKNOWN, None max_coeff = max(max_coeff, coeff) check_range = 30 for base in range(max_coeff + 1, max_coeff + 1 + check_range): val = f.subs(VAR_X, base) if sympy.isprime(val) and (not self.max_p or val < self.max_p): return IRREDUCIBLE, {"base": base, "p": val} return UNKNOWN, None if __name__ == '__main__': poly = create_polynomial(sys.argv[1]) check_common(poly, sys.argv[1], CohnCriterion())
class LevitCriterion: def __init__(self): self.name = "Levit's irreducibility criterion" def name(self): return self.name def check(self, f): # Levit, Irreducibility of Polynomials with Low Absolute Values, Theorem 2 n = f.degree() N = (n + 1) // 2 suitable = [] rhs = RisingFactorial((n//2)/2, N) / (2 ** (N-1)) for a in range(-20, 20 + 1): val = abs(f.eval(a)) if val == 0: # clearly this is reducible... return REDUCIBLE, None if val < rhs: suitable.append(a) if len(suitable) >= n: return IRREDUCIBLE, {'a': suitable} return UNKNOWN, None if __name__ == '__main__': poly = create_polynomial(sys.argv[1]) check_common(poly, sys.argv[1], LevitCriterion())
last = points[-1] x_diff = abs(first[0] - last[0]) y_diff = abs(first[1] - last[1]) if sympy.gcd(x_diff, y_diff) != 1: continue # now just check if all the other points are above this line x1 = first[0] y1 = first[1] x2 = last[0] y2 = last[1] above = True for i in range(1, len(points) - 1): x, y = points[i] if (y - y1) * (x2 - x1) <= (x - x1) * (y2 - y1): above = False break if not above: continue satisfies.append(p) if satisfies: return IRREDUCIBLE, {"p": satisfies} return UNKNOWN, None if __name__ == '__main__': poly = create_polynomial(sys.argv[1]) check_common(poly, sys.argv[1], DumasCriterion())