def check(self, f, force_prime=None): # try for prime divisors of constant term (might add leading term later too) const_coeff = abs(f.TC()) if const_coeff == 0: return REDUCIBLE, None if force_prime is not None: if const_coeff % force_prime != 0: return UNKNOWN, None primes = [force_prime] else: primes = sympy.ntheory.factorint(const_coeff) satisfies = [] for p in primes: # calculate points for given prime p for all coeffs points = [] for exp, coeff in poly_non_zero_exps(f): if coeff != 0: coeff_factors = sympy.ntheory.factorint(coeff) padic = coeff_factors[p] if p in coeff_factors else 0 points.append((exp, padic)) # if this can be of any use, length of line between end points must not cross any integers first = points[0] 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
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
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: return IRREDUCIBLE, None return UNKNOWN, None
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
def check(self, f): # Polynomials - Prasolov - Theorem 2.2.7 ([Os1]) part b) lead_coeff = f.LC() if lead_coeff != 1: return UNKNOWN, None const_coeff = abs(f.TC()) if not sympy.isprime(const_coeff): return UNKNOWN, None if self.max_p and const_coeff >= self.max_p: return UNKNOWN, None s = 0 for exp, coeff in poly_non_zero_exps(f): if exp != f.degree() and exp != 0: s += abs(coeff) if const_coeff < 1 + s: return UNKNOWN, None import mpmath # 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
def check(self, f): # Polynomials - Prasolov - Theorem 2.2.7 ([Os1]) part a) lead_coeff = f.LC() if lead_coeff != 1: return UNKNOWN, None const_coeff = abs(f.TC()) if not sympy.isprime(const_coeff): return UNKNOWN, None if self.max_p and const_coeff >= self.max_p: return UNKNOWN, None s = 0 for exp, coeff in poly_non_zero_exps(f): if exp != f.degree() and exp != 0: s += abs(coeff) if const_coeff > 1 + s: return IRREDUCIBLE, {'s': const_coeff} return UNKNOWN, None
def check(self, f): # see https://www.lehigh.edu/~shw2/preprints/eisenstein.pdf, # and https://math.stackexchange.com/questions/3589657/prove-polynomial-is-irreducible/3590300#3590300 const_coeff = f.TC() if const_coeff == 0: return REDUCIBLE, None linear_coeff = get_coeff(f, 1) if linear_coeff == 0: return UNKNOWN, None primes = sympy.ntheory.factorint(linear_coeff) for p in primes: power = primes[p] 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