• ## sage/misc/classgraph.py

# HG changeset patch
# User Jeroen Demeyer <jdemeyer@cage.ugent.be>
# Date 1385718102 -3600
# Node ID f3185fb2a16984a691df7be3d086d79286c58854
# Parent  f9d6bda1ed496ffcb74233d389f6499535f56539
Fix p-adic factorizations for non-squarefree polynomials

diff --git a/sage/misc/classgraph.py b/sage/misc/classgraph.py
 a sage: from sage.rings.polynomial.padics import polynomial_padic_capped_relative_dense, polynomial_padic_flat sage: G = class_graph(sage.rings.polynomial.padics); G Digraph on 4 vertices Digraph on 6 vertices sage: G.vertices() ['Polynomial_generic_dense', 'Polynomial_generic_domain', 'Polynomial_padic_capped_relative_dense', 'Polynomial_padic_flat'] ['Polynomial', 'Polynomial_generic_dense', 'Polynomial_generic_domain', 'Polynomial_padic', 'Polynomial_padic_capped_relative_dense', 'Polynomial_padic_flat'] sage: G.edges(labels=False) [('Polynomial_padic_capped_relative_dense', 'Polynomial_generic_domain'), ('Polynomial_padic_flat', 'Polynomial_generic_dense')] [('Polynomial_padic', 'Polynomial'), ('Polynomial_padic_capped_relative_dense', 'Polynomial_generic_domain'), ('Polynomial_padic_capped_relative_dense', 'Polynomial_padic'), ('Polynomial_padic_flat', 'Polynomial_generic_dense'), ('Polynomial_padic_flat', 'Polynomial_padic')] We construct the inheritance graph of a given class:: can be emulated by setting the option as_graph to False:: sage: class_graph(sage.rings.polynomial.padics, depth=2, as_graph=False) {'Polynomial_padic_capped_relative_dense': ['Polynomial_generic_domain'], 'Polynomial_padic_flat': ['Polynomial_generic_dense']} {'Polynomial_padic': ['Polynomial'], 'Polynomial_padic_capped_relative_dense': ['Polynomial_generic_domain', 'Polynomial_padic'], 'Polynomial_padic_flat': ['Polynomial_generic_dense', 'Polynomial_padic']} .. note:: the classes and as_graph options are mostly intended for internal recursive use. TESTS:: sage: G = class_graph(sage.rings.polynomial.padics, depth=2); G Digraph on 4 vertices Digraph on 6 vertices """ # This function descends recursively down the submodules of the # top module (if top is a module) and then down the hierarchy

diff --git a/sage/rings/padics/factory.py b/sage/rings/padics/factory.py
 a sage: P. = ZZ[] sage: R. = Zq(27, modulus = x^3 + 2*x + 1); R.modulus() (1 + O(3^20))*x^3 + (2 + O(3^20))*x + (1 + O(3^20)) (1 + O(3^20))*x^3 + (O(3^20))*x^2 + (2 + O(3^20))*x + (1 + O(3^20)) sage: P. = QQ[] sage: S. = Zq(27, modulus = x^3 + 2/7*x + 1) sage: P. = Zp(3)[] sage: x = var('x') sage: X. = Zq(27, modulus = x^3 + 2*x + 1); X.modulus() (1 + O(3^20))*x^3 + (2 + O(3^20))*x + (1 + O(3^20)) (1 + O(3^20))*x^3 + (O(3^20))*x^2 + (2 + O(3^20))*x + (1 + O(3^20)) sage: X == R True sage: GF(125, 'a').modulus() x^3 + 3*x + 3 sage: Y. = Zq(125); Y.modulus() (1 + O(5^20))*x^3 + (3 + O(5^20))*x + (3 + O(5^20)) (1 + O(5^20))*x^3 + (O(5^20))*x^2 + (3 + O(5^20))*x + (3 + O(5^20)) However, you can choose another polynomial if desired (as long as the reduction to \mathbb{F}_p[x] is irreducible).::

diff --git a/sage/rings/padics/local_generic.py b/sage/rings/padics/local_generic.py
 a EXAMPLES:: sage: R = Zp(3, 3, 'fixed-mod'); R.defining_polynomial('foo') (1 + O(3^3))*foo (1 + O(3^3))*foo + (O(3^3)) """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing return PolynomialRing(self, var).gen()

diff --git a/sage/rings/padics/padic_ZZ_pX_CA_element.pyx b/sage/rings/padics/padic_ZZ_pX_CA_element.pyx
 a sage: S. = ZZ[] sage: f = x^5 + 75*x^3 - 15*x^2 +125*x - 5 sage: W. = R.ext(f); W Eisenstein Extension of 5-adic Ring with capped absolute precision 5 in w defined by (1 + O(5^5))*x^5 + (3*5^2 + O(5^5))*x^3 + (2*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5))*x^2 + (5^3 + O(5^5))*x + (4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5)) Eisenstein Extension of 5-adic Ring with capped absolute precision 5 in w defined by (1 + O(5^5))*x^5 + (O(5^5))*x^4 + (3*5^2 + O(5^5))*x^3 + (2*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5))*x^2 + (5^3 + O(5^5))*x + (4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5)) sage: z = (1+w)^5; z 1 + w^5 + w^6 + 2*w^7 + 4*w^8 + 3*w^10 + w^12 + 4*w^13 + 4*w^14 + 4*w^15 + 4*w^16 + 4*w^17 + 4*w^20 + w^21 + 4*w^24 + O(w^25) sage: y = z >> 1; y

diff --git a/sage/rings/padics/padic_ZZ_pX_FM_element.pyx b/sage/rings/padics/padic_ZZ_pX_FM_element.pyx
 a sage: S. = R[] sage: f = x^5 + 75*x^3 - 15*x^2 +125*x - 5 sage: W. = R.ext(f); W Eisenstein Extension of 5-adic Ring of fixed modulus 5^5 in w defined by (1 + O(5^5))*x^5 + (3*5^2 + O(5^5))*x^3 + (2*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5))*x^2 + (5^3 + O(5^5))*x + (4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5)) Eisenstein Extension of 5-adic Ring of fixed modulus 5^5 in w defined by (1 + O(5^5))*x^5 + (O(5^5))*x^4 + (3*5^2 + O(5^5))*x^3 + (2*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5))*x^2 + (5^3 + O(5^5))*x + (4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5)) sage: z = (1+w)^5; z 1 + w^5 + w^6 + 2*w^7 + 4*w^8 + 3*w^10 + w^12 + 4*w^13 + 4*w^14 + 4*w^15 + 4*w^16 + 4*w^17 + 4*w^20 + w^21 + 4*w^24 + O(w^25) sage: y = z >> 1; y sage: y = ~z; y # indirect doctest 1 + 4*w^5 + 4*w^6 + 3*w^7 + w^8 + 2*w^10 + w^11 + w^12 + 2*w^14 + 3*w^16 + 3*w^17 + 4*w^18 + 4*w^19 + 2*w^20 + 2*w^21 + 4*w^22 + 3*w^23 + 3*w^24 + O(w^25) sage: y.parent() Eisenstein Extension of 5-adic Ring of fixed modulus 5^5 in w defined by (1 + O(5^5))*x^5 + (3*5^2 + O(5^5))*x^3 + (2*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5))*x^2 + (5^3 + O(5^5))*x + (4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5)) Eisenstein Extension of 5-adic Ring of fixed modulus 5^5 in w defined by (1 + O(5^5))*x^5 + (O(5^5))*x^4 + (3*5^2 + O(5^5))*x^3 + (2*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5))*x^2 + (5^3 + O(5^5))*x + (4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5)) sage: z = z - 1 sage: ~z Traceback (most recent call last): sage: y = ~z; y # indirect doctest 1 + 4*w^5 + 4*w^6 + 3*w^7 + w^8 + 2*w^10 + w^11 + w^12 + 2*w^14 + 3*w^16 + 3*w^17 + 4*w^18 + 4*w^19 + 2*w^20 + 2*w^21 + 4*w^22 + 3*w^23 + 3*w^24 + O(w^25) sage: y.parent() Eisenstein Extension of 5-adic Ring of fixed modulus 5^5 in w defined by (1 + O(5^5))*x^5 + (3*5^2 + O(5^5))*x^3 + (2*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5))*x^2 + (5^3 + O(5^5))*x + (4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5)) Eisenstein Extension of 5-adic Ring of fixed modulus 5^5 in w defined by (1 + O(5^5))*x^5 + (O(5^5))*x^4 + (3*5^2 + O(5^5))*x^3 + (2*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5))*x^2 + (5^3 + O(5^5))*x + (4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5)) sage: z = z - 1 sage: ~z Traceback (most recent call last):

diff --git a/sage/rings/padics/padic_extension_leaves.py b/sage/rings/padics/padic_extension_leaves.py
 a EXAMPLES:: sage: R. = ZqCA(27,10000); R #indirect doctest Unramified Extension of 3-adic Ring with capped absolute precision 10000 in a defined by (1 + O(3^10000))*x^3 + (2 + O(3^10000))*x + (1 + O(3^10000)) Unramified Extension of 3-adic Ring with capped absolute precision 10000 in a defined by (1 + O(3^10000))*x^3 + (O(3^10000))*x^2 + (2 + O(3^10000))*x + (1 + O(3^10000)) sage: R. = ZqCA(next_prime(10^30)^3, 3); R.prime() 1000000000000000000000000000057 EXAMPLES:: sage: R. = ZqFM(27,10000); R #indirect doctest Unramified Extension of 3-adic Ring of fixed modulus 3^10000 in a defined by (1 + O(3^10000))*x^3 + (2 + O(3^10000))*x + (1 + O(3^10000)) Unramified Extension of 3-adic Ring of fixed modulus 3^10000 in a defined by (1 + O(3^10000))*x^3 + (O(3^10000))*x^2 + (2 + O(3^10000))*x + (1 + O(3^10000)) sage: R. = ZqFM(next_prime(10^30)^3, 3); R.prime() 1000000000000000000000000000057 sage: R = ZpCA(3, 10000, print_pos=False); S. = ZZ[]; f = x^3 + 9*x - 3 sage: W. = R.ext(f); W #indirect doctest Eisenstein Extension of 3-adic Ring with capped absolute precision 10000 in w defined by (1 + O(3^10000))*x^3 + (3^2 + O(3^10000))*x + (-3 + 3^10000 + O(3^10000)) Eisenstein Extension of 3-adic Ring with capped absolute precision 10000 in w defined by (1 + O(3^10000))*x^3 + (O(3^10000))*x^2 + (3^2 + O(3^10000))*x + (-3 + 3^10000 + O(3^10000)) sage: W.precision_cap() 30000 sage: R = ZpFM(3, 10000, print_pos=False); S. = ZZ[]; f = x^3 + 9*x - 3 sage: W. = R.ext(f); W #indirect doctest Eisenstein Extension of 3-adic Ring of fixed modulus 3^10000 in w defined by (1 + O(3^10000))*x^3 + (3^2 + O(3^10000))*x + (-3 + 3^10000 + O(3^10000)) Eisenstein Extension of 3-adic Ring of fixed modulus 3^10000 in w defined by (1 + O(3^10000))*x^3 + (O(3^10000))*x^2 + (3^2 + O(3^10000))*x + (-3 + 3^10000 + O(3^10000)) sage: W.precision_cap() 30000

diff --git a/sage/rings/padics/tutorial.py b/sage/rings/padics/tutorial.py
 a sage: R. = Zq(125, prec = 20); R Unramified Extension of 5-adic Ring with capped absolute precision 20 in c defined by (1 + O(5^20))*x^3 + (3 + O(5^20))*x + (3 + O(5^20)) in c defined by (1 + O(5^20))*x^3 + (O(5^20))*x^2 + (3 + O(5^20))*x + (3 + O(5^20)) Eisenstein Extensions ---------------------

diff --git a/sage/rings/padics/unramified_extension_generic.py b/sage/rings/padics/unramified_extension_generic.py
 a EXAMPLES:: sage: R. = Zq(125); R #indirect doctest Unramified Extension of 5-adic Ring with capped absolute precision 20 in a defined by (1 + O(5^20))*x^3 + (3 + O(5^20))*x + (3 + O(5^20)) Unramified Extension of 5-adic Ring with capped absolute precision 20 in a defined by (1 + O(5^20))*x^3 + (O(5^20))*x^2 + (3 + O(5^20))*x + (3 + O(5^20)) sage: latex(R) #indirect doctest \mathbf{Z}_{5^{3}} """

diff --git a/sage/rings/polynomial/padics/polynomial_padic.py b/sage/rings/polynomial/padics/polynomial_padic.py
new file mode 100644
 - """ Base class for generic p-adic polynomials This provides common functionality for all p-adic polynomials, such as printing and factoring. AUTHORS: - Jeroen Demeyer (2013-11-22): initial version, split off from other files, made Polynomial_padic the common base class for all p-adic polynomials. """ #***************************************************************************** #       Copyright (C) 2007 David Roe #       Copyright (C) 2013 Jeroen Demeyer # #  Distributed under the terms of the GNU General Public License (GPL) #  as published by the Free Software Foundation; either version 2 of #  the License, or (at your option) any later version. #                  http://www.gnu.org/licenses/ #***************************************************************************** from sage.rings.padics.precision_error import PrecisionError from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.infinity import infinity class Polynomial_padic(Polynomial): def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): Polynomial.__init__(self, parent, is_gen, construct) def _repr(self, name=None): r""" EXAMPLES:: sage: R. = PolynomialRing(Zp(5, prec=5, type = 'capped-abs', print_mode = 'val-unit')) sage: f = 24 + R(4/3)*w + w^4 sage: f._repr() '(1 + O(5^5))*w^4 + (O(5^5))*w^3 + (O(5^5))*w^2 + (1043 + O(5^5))*w + (24 + O(5^5))' sage: f._repr(name='z') '(1 + O(5^5))*z^4 + (O(5^5))*z^3 + (O(5^5))*z^2 + (1043 + O(5^5))*z + (24 + O(5^5))' TESTS:: sage: k = Qp(5,10) sage: R. = k[] sage: f = R([k(0,-3), 0, k(0,-1)]); f (O(5^-1))*x^2 + (O(5^-3)) sage: f + f (O(5^-1))*x^2 + (O(5^-3)) AUTHOR: - David Roe (2007-03-03), based on Polynomial_generic_dense._repr() """ s = "" coeffs = self.list() if name is None: name = self.parent().variable_name() for n in reversed(xrange(len(coeffs))): x = coeffs[n] if x.valuation() != infinity: if s: s += " + " x = "(%s)"%repr(x) if n > 1: var = "*%s^%s"%(name,n) elif n==1: var = "*%s"%name else: var = "" s += (x + var) return s or "0" def factor(self): """ Return the factorization of this polynomial. EXAMPLES:: sage: R. = PolynomialRing(Qp(3,3,print_mode='terse',print_pos=False)) sage: pol = t^8 - 1 sage: for p,e in pol.factor(): print e, p 1 (1 + O(3^3))*t + (1 + O(3^3)) 1 (1 + O(3^3))*t + (-1 + O(3^3)) 1 (1 + O(3^3))*t^2 + (5 + O(3^3))*t + (-1 + O(3^3)) 1 (1 + O(3^3))*t^2 + (-5 + O(3^3))*t + (-1 + O(3^3)) 1 (1 + O(3^3))*t^2 + (1 + O(3^3)) sage: R. = PolynomialRing(Qp(5,6,print_mode='terse',print_pos=False)) sage: pol = 100 * (5*t - 1) * (t - 5) sage: pol (500 + O(5^9))*t^2 + (-2600 + O(5^8))*t + (500 + O(5^9)) sage: pol.factor() (500 + O(5^9)) * ((1 + O(5^5))*t + (-1/5 + O(5^5))) * ((1 + O(5^6))*t + (-5 + O(5^6))) sage: pol.factor().value() (500 + O(5^8))*t^2 + (-2600 + O(5^8))*t + (500 + O(5^8)) The same factorization over \ZZ_p. In this case, the "unit" part is a p-adic unit and the power of p is considered to be a factor:: sage: R. = PolynomialRing(Zp(5,6,print_mode='terse',print_pos=False)) sage: pol = 100 * (5*t - 1) * (t - 5) sage: pol (500 + O(5^9))*t^2 + (-2600 + O(5^8))*t + (500 + O(5^9)) sage: pol.factor() (4 + O(5^6)) * ((5 + O(5^7)))^2 * ((1 + O(5^6))*t + (-5 + O(5^6))) * ((5 + O(5^6))*t + (-1 + O(5^6))) sage: pol.factor().value() (500 + O(5^8))*t^2 + (-2600 + O(5^8))*t + (500 + O(5^8)) In the following example, the discriminant is zero, so the p-adic factorization is not well defined:: sage: factor(t^2) Traceback (most recent call last): ... PrecisionError: p-adic factorization not well-defined since the discriminant is zero up to the requestion p-adic precision More examples over \ZZ_p:: sage: R. = PolynomialRing(Zp(5, prec=6, type = 'capped-abs', print_mode = 'val-unit')) sage: f = w^5-1 sage: f.factor() ((1 + O(5^6))*w + (3124 + O(5^6))) * ((1 + O(5^6))*w^4 + (12501 + O(5^6))*w^3 + (9376 + O(5^6))*w^2 + (6251 + O(5^6))*w + (3126 + O(5^6))) See :trac:4038:: sage: E = EllipticCurve('37a1') sage: K =Qp(7,10) sage: EK = E.base_extend(K) sage: E = EllipticCurve('37a1') sage: K = Qp(7,10) sage: EK = E.base_extend(K) sage: g = EK.division_polynomial_0(3) sage: g.factor() (3 + O(7^10)) * ((1 + O(7^10))*x + (1 + 2*7 + 4*7^2 + 2*7^3 + 5*7^4 + 7^5 + 5*7^6 + 3*7^7 + 5*7^8 + 3*7^9 + O(7^10))) * ((1 + O(7^10))*x^3 + (6 + 4*7 + 2*7^2 + 4*7^3 + 7^4 + 5*7^5 + 7^6 + 3*7^7 + 7^8 + 3*7^9 + O(7^10))*x^2 + (6 + 3*7 + 5*7^2 + 2*7^4 + 7^5 + 7^6 + 2*7^8 + 3*7^9 + O(7^10))*x + (2 + 5*7 + 4*7^2 + 2*7^3 + 6*7^4 + 3*7^5 + 7^6 + 4*7^7 + O(7^10))) TESTS: Check that :trac:13293 is fixed:: sage: R. = Qp(3)[] sage: f = 1926*T^2 + 312*T + 387 sage: f.factor() (3^2 + 2*3^3 + 2*3^4 + 3^5 + 2*3^6 + O(3^22)) * ((1 + O(3^19))*T + (2*3^-1 + 3 + 3^2 + 2*3^5 + 2*3^6 + 2*3^7 + 3^8 + 3^9 + 2*3^11 + 3^15 + 3^17 + O(3^19))) * ((1 + O(3^20))*T + (2*3 + 3^2 + 3^3 + 3^5 + 2*3^6 + 2*3^7 + 3^8 + 3^10 + 3^11 + 2*3^12 + 2*3^14 + 2*3^15 + 2*3^17 + 2*3^18 + O(3^20))) """ if self == 0: raise ArithmeticError("factorization of 0 not defined") # Scale self such that 0 is the lowest valuation # amongst the coefficients try: val = self.valuation(val_of_var=0) except TypeError: val = min([c.valuation() for c in self]) self_normal = self / self.base_ring().uniformizer_pow(val) absprec = min([x.precision_absolute() for x in self_normal]) if self_normal.discriminant().valuation() >= absprec: raise PrecisionError( "p-adic factorization not well-defined since the discriminant is zero up to the requestion p-adic precision") G = self_normal._pari_().factorpadic(self.base_ring().prime(), absprec) return _pari_padic_factorization_to_sage(G, self.parent(), self.leading_coefficient()) def _pari_padic_factorization_to_sage(G, R, leading_coeff): """ Given a PARI factorization matrix G representing a factorization of some polynomial in the p-adic polynomial ring R, return the corresponding Sage factorization. All factors in G are assumed to have content 1 (this is how PARI returns its factorizations). INPUT: - G -- PARI factorization matrix, returned by factorpadic. - R -- polynomial ring to be used as parent ring of the factors - leading_coeff -- leading coefficient of the polynomial which was factored. This can belong to any ring which can be coerced into R.base_ring(). OUTPUT: - A Sage :class:Factorization. """ B = R.base_ring() p = B.prime() leading_coeff = B(leading_coeff) pols = [R(f, absprec=f.padicprec(p)) for f in G[0]] exps = [int(e) for e in G[1]] # Determine unit part (which is discarded by PARI) if B.is_field(): # When the base ring is a field, we normalize # the irreducible factors so they have leading # coefficient 1. for i in xrange(len(pols)): lc = pols[i].leading_coefficient() lc = lc.lift_to_precision()  # Ensure we don't lose precision pols[i] *= ~lc else: # When the base ring is not a field, we normalize # the irreducible factors so that the leading term # is a power of p. c, leading_coeff = leading_coeff.val_unit() for i in xrange(len(pols)): v, upart = pols[i].leading_coefficient().val_unit() upart = upart.lift_to_precision()  # Ensure we don't lose precision pols[i] *= ~upart c -= exps[i] * v if c: # Add factor p^c pols.append(R(p)) exps.append(c) from sage.structure.factorization import Factorization return Factorization(zip(pols, exps), leading_coeff)

diff --git a/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py b/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py

diff --git a/sage/rings/polynomial/padics/polynomial_padic_flat.py b/sage/rings/polynomial/padics/polynomial_padic_flat.py
 a from sage.rings.integer import Integer """ p-adic Flat Polynomials """ #***************************************************************************** #  Distributed under the terms of the GNU General Public License (GPL) #  as published by the Free Software Foundation; either version 2 of #  the License, or (at your option) any later version. #                  http://www.gnu.org/licenses/ #***************************************************************************** from sage.rings.polynomial.polynomial_element import Polynomial_generic_dense, Polynomial from sage.rings.polynomial.padics.polynomial_padic import Polynomial_padic from sage.rings.infinity import infinity from sage.libs.all import pari_gen from sage.structure.factorization import Factorization import sage.rings.padics.misc class Polynomial_padic_flat(Polynomial_generic_dense): class Polynomial_padic_flat(Polynomial_generic_dense, Polynomial_padic): def __init__(self, parent, x=None, check=True, is_gen=False, construct=False, absprec=None): """ Initialization function for the class  Polynomial_padic_flat. Initialization function for the class Polynomial_padic_flat. """ if x is None: Polynomial_generic_dense.__init__(self, parent, x = None, is_gen = is_gen) Polynomial_generic_dense.__init__(self, parent, x, check, is_gen, construct) return R = parent.base_ring() if sage.rings.fraction_field_element.is_FractionFieldElement(x): absprec = infinity m = min([a.precision_absolute() for a in x] + [absprec]) Polynomial_generic_dense.__init__(self, parent, x, absprec = m) def _mul_(self, right): """ Returns the product of this Polynomial_padic_flat by right. """ return self._mul_generic(right) def _repr(self, name=None): r""" EXAMPLES: sage: R. = PolynomialRing(Zp(5, prec=5, type = 'capped-abs', print_mode = 'val-unit')) sage: f = 24 + R(4/3)*w + w^4 sage: f._repr() '(1 + O(5^5))*w^4 + (1043 + O(5^5))*w + (24 + O(5^5))' sage: f._repr(name='z') '(1 + O(5^5))*z^4 + (1043 + O(5^5))*z + (24 + O(5^5))' AUTHOR: -- David Roe (2007-03-03), based on Polynomial_generic_dense._repr() """ s = " " n = m = self.degree() if name is None: name = self.parent().variable_name() #atomic_repr = self.parent().base_ring()._repr_option('element_is_atomic') coeffs = self.list() for x in reversed(coeffs): if x != 0: if n != m: s += " + " #x = repr(x) x = "(%s)"%x if n > 1: var = "*%s^%s"%(name,n) elif n==1: var = "*%s"%name else: var = "" s += "%s%s"%(x,var) n -= 1 if s==" ": return "0" return s[1:] def factor(self, absprec = None): r""" Returns the factorization of this Polynomial_padic_flat. EXAMPLES: sage: R. = PolynomialRing(Zp(5, prec=5, type = 'capped-abs', print_mode = 'val-unit')) sage: f = w^5-1 sage: f.factor() ((1 + O(5^5))*w + (624 + O(5^5))) * ((1 + O(5^5))*w^4 + (2501 + O(5^5))*w^3 + (1876 + O(5^5))*w^2 + (1251 + O(5^5))*w + (626 + O(5^5))) See \#4038: sage: E = EllipticCurve('37a1') sage: K =Qp(7,10) sage: EK = E.base_extend(K) sage: E = EllipticCurve('37a1') sage: K = Qp(7,10) sage: EK = E.base_extend(K) sage: g = EK.division_polynomial_0(3) sage: g.factor() (3 + O(7^10)) * ((1 + O(7^10))*x + (1 + 2*7 + 4*7^2 + 2*7^3 + 5*7^4 + 7^5 + 5*7^6 + 3*7^7 + 5*7^8 + 3*7^9 + O(7^10))) * ((1 + O(7^10))*x^3 + (6 + 4*7 + 2*7^2 + 4*7^3 + 7^4 + 5*7^5 + 7^6 + 3*7^7 + 7^8 + 3*7^9 + O(7^10))*x^2 + (6 + 3*7 + 5*7^2 + 2*7^4 + 7^5 + 7^6 + 2*7^8 + 3*7^9 + O(7^10))*x + (2 + 5*7 + 4*7^2 + 2*7^3 + 6*7^4 + 3*7^5 + 7^6 + 4*7^7 + O(7^10))) TESTS: Check that :trac:13293 is fixed:: sage: R.=Qp(3)[] sage: f=1926*T^2 + 312*T + 387 sage: f.factor() (1 + 2*3 + 2*3^2 + 3^3 + 2*3^4 + O(3^20)) * ((3 + O(3^21))) * ((1 + O(3^20))*T + (2*3 + 3^2 + 3^3 + 3^5 + 2*3^6 + 2*3^7 + 3^8 + 3^10 + 3^11 + 2*3^12 + 2*3^14 + 2*3^15 + 2*3^17 + 2*3^18 + 3^20 + O(3^21))) * ((3 + O(3^21))*T + (2 + 3^2 + 3^3 + 2*3^6 + 2*3^7 + 2*3^8 + 3^9 + 3^10 + 2*3^12 + 3^16 + 3^18 + O(3^20))) """ if self == 0: raise ValueError, "Factorization of 0 not defined" if absprec is None: absprec = min([x.precision_absolute() for x in self.list()]) else: absprec = Integer(absprec) if absprec <= 0: raise ValueError, "absprec must be positive" G = self._pari_().factorpadic(self.base_ring().prime(), absprec) pols = G[0] exps = G[1] F = [] R = self.parent() for i in xrange(len(pols)): f = R(pols[i], absprec = absprec) e = int(exps[i]) F.append((f,e)) #if R.base_ring().is_field(): #    # When the base ring is a field we normalize #    # the irreducible factors so they have leading #    # coefficient 1. #    for i in range(len(F)): #        cur = F[i][0].leading_coefficient() #        if cur != 1: #            F[i] = (F[i][0].monic(), F[i][1]) #    return Factorization(F, self.leading_coefficient()) #else: #    # When the base ring is not a field, we normalize #    # the irreducible factors so that the leading term #    # is a power of p.  We also ensure that the gcd of #    # the coefficients of each term is 1. c = self.leading_coefficient().valuation() u = self.base_ring()(1) for i in range(len(F)): upart = F[i][0].leading_coefficient().unit_part().lift_to_precision(absprec) lval = F[i][0].leading_coefficient().valuation() if upart != 1: F[i] = (F[i][0] / upart, F[i][1]) u *= upart ** F[i][1] c -= lval * F[i][1] if c != 0: F.append((self.parent()(self.base_ring().prime_pow(c)), 1)) u = u.add_bigoh(absprec - c) return Factorization(F, u)
• ## sage/rings/polynomial/polynomial_element.pyx

diff --git a/sage/rings/polynomial/polynomial_element.pyx b/sage/rings/polynomial/polynomial_element.pyx
 a from sage.rings.rational_field import QQ, is_RationalField from sage.rings.integer_ring import ZZ, is_IntegerRing from sage.rings.fraction_field import is_FractionField from sage.rings.padics.generic_nodes import is_pAdicRing, is_pAdicField from sage.rings.integral_domain import is_IntegralDomain from sage.structure.parent_gens cimport ParentWithGens newself = bigring(self) newother = bigring(other) return self.parent().base_ring()(newself.resultant(newother,bigring(self.parent().gen()))) # Main variable is "x": we can use PARI to compute the resultant res = self._pari_with_name().polresultant(other._pari_with_name(), variable) # Single-variable polynomial or main variable is "x": we can use PARI to compute the resultant res = self._pari_with_name().polresultant(other._pari_with_name()) return self.parent().base_ring()(res) def discriminant(self): 54 sage: ZZ.quo(9)[x](2*x^3 + x^2 + x).discriminant() 2 This was fixed by :trac:15422:: sage: R. = PolynomialRing(Qp(2)) sage: (s^2).discriminant() 0 """ if self.is_zero(): return self.parent().zero_element() Traceback (most recent call last): ... TypeError: Cannot evaluate symbolic expression to a numeric value. We can find roots of polynomials defined over \ZZ or \QQ over the p-adics, see :trac:15422:: sage: R. = ZZ[] sage: pol = (x - 1)^2 sage: pol.roots(Qp(3,5)) [(1 + O(3^5), 2)] This doesn't work if we first change coefficients to \QQ_p:: sage: pol.change_ring(Qp(3,5)).roots() Traceback (most recent call last): ... PrecisionError: p-adic factorization not well-defined since the discriminant is zero up to the requestion p-adic precision sage: (pol - 3^6).roots(Qp(3,5)) [(1 + 2*3^3 + 2*3^4 + O(3^5), 1), (1 + 3^3 + O(3^5), 1)] sage: r = pol.roots(Zp(3,5), multiplicities=False); r [1 + O(3^5)] sage: parent(r[0]) 3-adic Ring with capped relative precision 5 """ K = self.parent().base_ring() if hasattr(K, '_roots_univariate_polynomial'): return K._roots_univariate_polynomial(self, ring=ring, multiplicities=multiplicities, algorithm=algorithm) seq = [] L = K if ring is None else ring late_import() if L != K or is_AlgebraicField_common(L): # So far, the only "special" implementations are for real # and complex root isolation. # and complex root isolation and for p-adic factorization if (is_IntegerRing(K) or is_RationalField(K) or is_AlgebraicRealField(K)) and \ (is_AlgebraicRealField(L) or is_RealIntervalField(L)): real_field = RealField(L.prec()) return self.change_ring(real_field).roots(ring=L, multiplicities=multiplicities, algorithm=algorithm) else: return self.change_ring(L).roots(multiplicities=multiplicities, algorithm=algorithm) elif is_pAdicRing(L) or is_pAdicField(L): p = L.prime() n = L.precision_cap() try: F = self.factor_padic(p, n) except AttributeError: pass else: return self.change_ring(L)._roots_from_factorization(F, multiplicities) return self.change_ring(L).roots(multiplicities=multiplicities, algorithm=algorithm) try: if K.is_integral_domain(): self = self//c except AttributeError: pass rts = self.factor() return self._roots_from_factorization(self.factor(), multiplicities) else: raise NotImplementedError except NotImplementedError: raise NotImplementedError("root finding for this polynomial not implemented") for fac in rts: def _roots_from_factorization(self, F, multiplicities): """ Given a factorization F of the polynomial self, return the roots of self. EXAMPLES:: sage: R. = ZZ[] sage: pol = 20*x^3 - 50*x^2 + 20*x sage: F = pol.factor(); F 2 * 5 * (x - 2) * x * (2*x - 1) sage: pol._roots_from_factorization(F, multiplicities=True) [(2, 1), (0, 1)] sage: pol.change_ring(QQ)._roots_from_factorization(F, multiplicities=False) [2, 0, 1/2] """ seq = [] K = self.parent().base_ring() for fac in F: g = fac[0] if g.degree() == 1: rt = -g[0]/g[1]
• ## sage/rings/polynomial/polynomial_element_generic.py

diff --git a/sage/rings/polynomial/polynomial_element_generic.py b/sage/rings/polynomial/polynomial_element_generic.py
• ## sage/rings/polynomial/polynomial_integer_dense_flint.pyx

diff --git a/sage/rings/polynomial/polynomial_integer_dense_flint.pyx b/sage/rings/polynomial/polynomial_integer_dense_flint.pyx
 a Return p-adic factorization of self to given precision. INPUT: - p -- prime - prec -- integer; the precision OUTPUT: factorization of self reduced modulo p. - factorization of self over the completion at p. EXAMPLES:: sage: f = x^2 + 1 sage: f.factor_padic(5, 4) ((1 + O(5^4))*x + (2 + 5 + 2*5^2 + 5^3 + O(5^4))) * ((1 + O(5^4))*x + (3 + 3*5 + 2*5^2 + 3*5^3 + O(5^4))) A more difficult example:: sage: f = 100 * (5*x + 1)^2 * (x + 5)^2 sage: f.factor_padic(5, 10) (4 + O(5^10)) * ((5 + O(5^11)))^2 * ((1 + O(5^10))*x + (5 + O(5^10)))^2 * ((5 + O(5^10))*x + (1 + O(5^10)))^2 """ from sage.rings.padics.factory import Zp p = Integer(p) if not p.is_prime(): raise ValueError, "p must be prime" prec = Integer(prec) if prec <= 0: raise ValueError, "prec must be positive" K = Zp(p, prec, type='capped-abs') # Parent field for coefficients and polynomial K = Zp(p, prec, type='capped-rel') R = K[self.parent().variable_name()] return R(self).factor() # Factor the *exact* polynomial using factorpadic() G = self._pari_with_name().factorpadic(p, prec) from sage.rings.polynomial.padics.polynomial_padic import _pari_padic_factorization_to_sage return _pari_padic_factorization_to_sage(G, R, self.leading_coefficient()) def list(self): """
• ## sage/rings/polynomial/polynomial_integer_dense_ntl.pyx

diff --git a/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx b/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx
 a def factor_padic(self, p, prec=10): """ Return p-adic factorization of self to given precision. Return p-adic factorization of self to given precision. INPUT: - p -- prime - prec -- integer; the precision OUTPUT: factorization of self reduced modulo p. OUTPUT: - factorization of self over the completion at p. EXAMPLES:: sage: f = x^2 + 1 sage: f.factor_padic(5, 4) ((1 + O(5^4))*x + (2 + 5 + 2*5^2 + 5^3 + O(5^4))) * ((1 + O(5^4))*x + (3 + 3*5 + 2*5^2 + 3*5^3 + O(5^4))) A more difficult example:: sage: f = 100 * (5*x + 1)^2 * (x + 5)^2 sage: f.factor_padic(5, 10) (4 + O(5^10)) * ((5 + O(5^11)))^2 * ((1 + O(5^10))*x + (5 + O(5^10)))^2 * ((5 + O(5^10))*x + (1 + O(5^10)))^2 """ from sage.rings.padics.factory import Zp p = Integer(p) if not p.is_prime(): raise ValueError, "p must be prime" prec = Integer(prec) if prec <= 0: raise ValueError, "prec must be positive" K = Zp(p, prec, type='capped-abs') # Parent field for coefficients and polynomial K = Zp(p, prec, type='capped-rel') R = K[self.parent().variable_name()] return R(self).factor() # Factor the *exact* polynomial using factorpadic() G = self._pari_with_name().factorpadic(p, prec) from sage.rings.polynomial.padics.polynomial_padic import _pari_padic_factorization_to_sage return _pari_padic_factorization_to_sage(G, R, self.leading_coefficient()) def list(self): """
• ## sage/rings/polynomial/polynomial_rational_flint.pyx

diff --git a/sage/rings/polynomial/polynomial_rational_flint.pyx b/sage/rings/polynomial/polynomial_rational_flint.pyx
 a def factor_padic(self, p, prec=10): """ Returns the p-adic factorization of this polynomial to the given Return the p-adic factorization of this polynomial to the given precision. INPUT: -  p - Prime number -  prec - Integer; the precision OUTPUT: -  Factorization of self viewed as a p-adic polynomial - factorization of self viewed as a p-adic polynomial EXAMPLES:: sage: R. = QQ[] sage: f = x^3 - 2 sage: f.factor_padic(2) (1 + O(2^10))*x^3 + (O(2^10))*x^2 + (O(2^10))*x + (2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + O(2^10)) (1 + O(2^10))*x^3 + (2 + 2^2 + 2^3 + 2^4 + 2^5 + 2^6 + 2^7 + 2^8 + 2^9 + O(2^10)) sage: f.factor_padic(3) (1 + O(3^10))*x^3 + (O(3^10))*x^2 + (O(3^10))*x + (1 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + O(3^10)) (1 + O(3^10))*x^3 + (1 + 2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + O(3^10)) sage: f.factor_padic(5) ((1 + O(5^10))*x + (2 + 4*5 + 2*5^2 + 2*5^3 + 5^4 + 3*5^5 + 4*5^7 + 2*5^8 + 5^9 + O(5^10))) * ((1 + O(5^10))*x^2 + (3 + 2*5^2 + 2*5^3 + 3*5^4 + 5^5 + 4*5^6 + 2*5^8 + 3*5^9 + O(5^10))*x + (4 + 5 + 2*5^2 + 4*5^3 + 4*5^4 + 3*5^5 + 3*5^6 + 4*5^7 + 4*5^9 + O(5^10))) The input polynomial is considered to have "infinite" precision, therefore the p-adic factorization of the polynomial is not the same as first coercing to Q_p and then factoring (see also :trac:15422):: sage: f = x^2 - 3^6 sage: f.factor_padic(3,5) ((1 + O(3^5))*x + (3^3 + O(3^5))) * ((1 + O(3^5))*x + (2*3^3 + 2*3^4 + O(3^5))) sage: f.change_ring(Qp(3,5)).factor() Traceback (most recent call last): ... PrecisionError: p-adic factorization not well-defined since the discriminant is zero up to the requestion p-adic precision A more difficult example:: sage: f = 100 * (5*x + 1)^2 * (x + 5)^2 sage: f.factor_padic(5, 10) (4*5^4 + O(5^14)) * ((1 + O(5^9))*x + (5^-1 + O(5^9)))^2 * ((1 + O(5^10))*x + (5 + O(5^10)))^2 Try some bogus inputs:: sage: f.factor_padic(3,-1) Traceback (most recent call last): ... ValueError: prec_cap must be non-negative. sage: f.factor_padic(6,10) Traceback (most recent call last): ... ValueError: p must be prime sage: f.factor_padic('hello', 'world') Traceback (most recent call last): ... TypeError: unable to convert x (=hello) to an integer """ from sage.rings.padics.factory import Qp p = Integer(p) if not p.is_prime(): raise ValueError, "p must be prime" prec = Integer(prec) if prec <= 0: raise ValueError, "prec must be positive" # Parent field for coefficients and polynomial K = Qp(p, prec, type='capped-rel') R = K[self.parent().variable_name()] return R(self).factor()  # absprec = prec # Factor the *exact* polynomial using factorpadic() G = self._pari_with_name().factorpadic(p, prec) from sage.rings.polynomial.padics.polynomial_padic import _pari_padic_factorization_to_sage return _pari_padic_factorization_to_sage(G, R, self.leading_coefficient()) def hensel_lift(self, p, e): r""" Assuming that this polynomial factors modulo p into distinct
• ## sage/tests/french_book/polynomes.py

diff --git a/sage/tests/french_book/polynomes.py b/sage/tests/french_book/polynomes.py
 a sage: p.roots(QQ) [(2, 2), (1/2, 2)] sage: p.roots(Zp(19, print_max_terms=3)) [(2 + 6*19^10 + 9*19^11 + ... + O(19^20), 1), (7 + 16*19 + 17*19^2 + ... + O(19^20), 1), (10 + 9*19 + 9*19^2 + ... + O(19^20), 1), (10 + 9*19 + 9*19^2 + ... + O(19^20), 1), [(7 + 16*19 + 17*19^2 + ... + O(19^20), 1), (12 + 2*19 + 19^2 + ... + O(19^20), 1), (2 + 13*19^10 + 9*19^11 + ... + O(19^20), 1)] (10 + 9*19 + 9*19^2 + ... + O(19^20), 2), (2 + O(19^20), 2)] Sage example in ./polynomes.tex, line 623::