def newton_polygon(self): r""" Returns a list of vertices of the Newton polygon of this polynomial. .. NOTE:: If some coefficients have not enough precision an error is raised. EXAMPLES:: sage: K = Qp(5) sage: R.<t> = K[] sage: f = 5 + 3*t + t^4 + 25*t^10 sage: f.newton_polygon() Finite Newton polygon with 4 vertices: (0, 1), (1, 0), (4, 0), (10, 2) sage: g = f + K(0,0)*t^4; g (5^2 + O(5^22))*t^10 + O(5^0)*t^4 + (3 + O(5^20))*t + 5 + O(5^21) sage: g.newton_polygon() Traceback (most recent call last): ... PrecisionError: The coefficient of t^4 has not enough precision TESTS: Check that :trac:`22936` is fixed:: sage: S.<x> = PowerSeriesRing(GF(5)) sage: R.<y> = S[] sage: p = x^2+y+x*y^2 sage: p.newton_polygon() Finite Newton polygon with 3 vertices: (0, 2), (1, 0), (2, 1) AUTHOR: - Xavier Caruso (2013-03-20) """ d = self.degree() from sage.geometry.newton_polygon import NewtonPolygon polygon = NewtonPolygon([(x, self[x].valuation()) for x in range(d+1)]) polygon_prec = NewtonPolygon([ (x, self[x].precision_absolute()) for x in range(d+1) ]) vertices = polygon.vertices(copy=False) vertices_prec = polygon_prec.vertices(copy=False) if len(vertices_prec) > 0: if vertices[0][0] > vertices_prec[0][0]: raise PrecisionError("first term with non-infinite valuation must have determined valuation") elif vertices[-1][0] < vertices_prec[-1][0]: raise PrecisionError("last term with non-infinite valuation must have determined valuation") else: for (x, y) in vertices: if polygon_prec(x) <= y: raise PrecisionError("The coefficient of %s^%s has not enough precision" % (self.parent().variable_name(), x)) return polygon
def __invert__(self): r""" Return the multiplicative inverse of this element. NOTE:: The result of division always lives in the fraction field, even if the element to be inverted is a unit. EXAMPLES:: sage: R = ZpLC(19) sage: x = R(-5/2, 5); x 7 + 9*19 + 9*19^2 + 9*19^3 + 9*19^4 + O(19^5) sage: y = ~x # indirect doctest sage: y 11 + 7*19 + 11*19^2 + 7*19^3 + 11*19^4 + O(19^5) sage: y == -2/5 True TESTS:: sage: a = R.random_element() sage: a * ~a == 1 True """ if self.is_zero(): raise PrecisionError("cannot invert something indistinguishable from zero") x_self = self._value x = self._parent._approx_one / x_self # dx = -(1/self^2)*dself dx = [ [self, self._parent._approx_minusone/(x_self*x_self)] ] return self.__class__(self._parent.fraction_field(), x, dx=dx, check=False)
def expansion(self, n=None, lift_mode='simple', start_val=None): r""" Return a list giving the `p`-adic expansion of this element. If this is a field element, start at `p^{\mbox{valuation}}`, if a ring element at `p^0`. INPUT: - ``n`` -- an integer or ``None`` (default ``None``); if given, return the corresponding entry in the expansion. - ``lift_mode`` -- a string (default: ``simple``); currently only ``simple`` is implemented. - ``start_val`` -- an integer or ``None`` (default: ``None``); start at this valuation rather than the default (`0` or the valuation of this element). EXAMPLES:: sage: R = ZpLC(5, 10) sage: x = R(123456789); x 4 + 2*5 + 5^2 + 4*5^3 + 5^5 + 5^6 + 5^8 + 3*5^9 + O(5^10) sage: x.expansion() [4, 2, 1, 4, 0, 1, 1, 0, 1, 3] sage: x.expansion(3) 4 sage: x.expansion(start_val=5) [1, 1, 0, 1, 3] If any, trailing zeros are included in the expansion:: sage: y = R(1234); y 4 + 5 + 4*5^2 + 4*5^3 + 5^4 + O(5^10) sage: y.expansion() [4, 1, 4, 4, 1, 0, 0, 0, 0, 0] """ if lift_mode != 'simple': raise NotImplementedError("Other modes than 'simple' are not implemented yet") prec = self.precision_absolute() val = self.valuation() expansion = self._value.list(prec) if n is not None: if n < val: return ZZ(0) try: return expansion[n-val] except KeyError: raise PrecisionError("The digit in position %s is not determined" % n) if start_val is None: if self._parent.is_field(): start_val = val else: start_val = 0 if start_val > val: return expansion[start_val-val:] else: return (val-start_val)*[ZZ(0)] + expansion
def _basic_integral(self, a, j): r""" Return `\int_{a+pZ_p} (z-{a})^j d\Phi(0-infty)`. See formula in section 9.2 of [PS2011]_ INPUT: - ``a`` -- integer in range(p) - ``j`` -- integer in range(self.symbol().precision_relative()) EXAMPLES:: sage: from sage.modular.pollack_stevens.padic_lseries import pAdicLseries sage: E = EllipticCurve('11a3') sage: L = E.padic_lseries(5, implementation="pollackstevens", precision=4) #long time sage: L._basic_integral(1,2) # long time 2*5^2 + 5^3 + O(5^4) """ symb = self.symbol() M = symb.precision_relative() if j > M: raise PrecisionError("Too many moments requested") p = self.prime() ap = symb.Tq_eigenvalue(p) D = self._quadratic_twist ap = ap * kronecker(D, p) K = pAdicField(p, M) symb_twisted = symb.evaluate_twisted(a, D) return sum( binomial(j, r) * ((a - ZZ(K.teichmuller(a)))**(j - r)) * (p**r) * symb_twisted.moment(r) for r in range(j + 1)) / ap
def __call__(self, x): r""" Evaluate this character at an element of `\ZZ_p^\times`. EXAMPLES: Exact answers are returned when this is possible:: sage: kappa = pAdicWeightSpace(29)(13, DirichletGroup(29, QQ).0) sage: kappa(1) 1 sage: kappa(0) 0 sage: kappa(12) -106993205379072 sage: kappa(-1) -1 sage: kappa(13 + 4*29 + 11*29^2 + O(29^3)) 9 + 21*29 + 27*29^2 + O(29^3) When the character chi is defined over a p-adic field, the results returned are inexact:: sage: kappa = pAdicWeightSpace(29)(13, DirichletGroup(29, Qp(29)).0^14) sage: kappa(1) 1 + O(29^20) sage: kappa(0) 0 sage: kappa(12) 17 + 11*29 + 7*29^2 + 4*29^3 + 5*29^4 + 2*29^5 + 13*29^6 + 3*29^7 + 18*29^8 + 21*29^9 + 28*29^10 + 28*29^11 + 28*29^12 + 28*29^13 + 28*29^14 + 28*29^15 + 28*29^16 + 28*29^17 + 28*29^18 + 28*29^19 + O(29^20) sage: kappa(12) == -106993205379072 True sage: kappa(-1) == -1 True sage: kappa(13 + 4*29 + 11*29^2 + O(29^3)) 9 + 21*29 + 27*29^2 + O(29^3) """ if isinstance(x, pAdicGenericElement): if x.parent().prime() != self._p: raise TypeError("x must be an integer or a %s-adic integer" % self._p) if self._p**(x.precision_absolute()) < self._chi.conductor(): raise PrecisionError("Precision too low") xint = x.lift() else: xint = x if (xint % self._p == 0): return 0 return self._chi(xint) * x**self._k
def _div_(self, other): r""" Return the quotient of this element and ``other``. NOTE:: The result of division always lives in the fraction field, even if the element to be inverted is a unit. EXAMPLES:: sage: R = ZpLC(19) sage: a = R(-1, 5); a 18 + 18*19 + 18*19^2 + 18*19^3 + 18*19^4 + O(19^5) sage: b = R(-5/2, 5); b 7 + 9*19 + 9*19^2 + 9*19^3 + 9*19^4 + O(19^5) sage: c = a / b # indirect doctest sage: c 8 + 11*19 + 7*19^2 + 11*19^3 + 7*19^4 + O(19^5) sage: c.parent() 19-adic Field with lattice-cap precision sage: a / (19*b) 8*19^-1 + 11 + 7*19 + 11*19^2 + 7*19^3 + O(19^4) If the division is indistinguishable from zero, an error is raised:: sage: c = a / (2*b + 5) Traceback (most recent call last): ... PrecisionError: cannot divide by something indistinguishable from zero """ if other.is_zero(): raise PrecisionError( "cannot divide by something indistinguishable from zero") x_self = self._value x_other = other._value x = x_self / x_other # dx = (1/other)*dself - (self/other^2)*dother dx = [[self, self._parent._approx_one / x_other], [other, -x_self / (x_other * x_other)]] return self.__class__(self._parent.fraction_field(), x, dx=dx, check=False)
def valuation(self, secure=False): r""" Return the valuation of this element. INPUT: - ``secure`` -- a boolean (default: ``False``); when ``True``, an error is raised if the precision on the element is not enough to determine for sure its valuation; otherwise the absolute precision (which is the smallest possible valuation) is returned EXAMPLES:: sage: R = ZpLC(2) sage: x = R(12, 10); x 2^2 + 2^3 + O(2^10) sage: x.valuation() 2 sage: y = x - x; y O(2^40) sage: y.valuation() 40 sage: y.valuation(secure=True) Traceback (most recent call last): ... PrecisionError: Not enough precision """ p = self._parent.prime() val = self._value.valuation() prec = self.precision_absolute() if val < prec: return val elif secure: raise PrecisionError("Not enough precision") else: return prec
def upper_bound_tate(cp, frob_matrix, precision, over_Qp=False, pedantic=True): """ Return a upper bound for Tate classes over characteristic 0 TODO: improove documentation """ p = cp.list()[-1].prime_factors()[0] # it would be nice to use QpLF OK = ZpCA(p, prec=precision) # adjust precision frob_matrix = matrix(OK, frob_matrix) # get the p-adic eigenvalues _, _, cyc_factorization = rank_fieldextension(cp) # a bit hacky val = [ min(elt.valuation() for elt in col) for col in frob_matrix.columns() ] projection_cols = frob_matrix.ncols() - val.index(0) assert set(val[-projection_cols:]) == {0} # P1 = | zero matrix | # | Identity | P1 = zero_matrix(frob_matrix.ncols() - projection_cols, projection_cols).stack(identity_matrix(projection_cols)) # computing a kernel, either via smith form or howell form # involves some kind of gauss elimination, # and thus having the columns with lowest valuation first improves # the numerical stability of the algorithms P1.reverse_rows_and_columns() frob_matrix.reverse_rows_and_columns() @cached_function def frob_power(k): if k == 0: return identity_matrix(frob_matrix.ncols()) elif k == 1: return frob_matrix else: return frob_matrix * frob_power(k - 1) factor_i = [] dim_Ti = [] obsi = [] dim_Li = [] for cyc_fac, cyc_exp in cyc_factorization: factor_i.append((cyc_fac, cyc_exp)) Ti = matrix(0, frob_matrix.ncols()) obsij = [] dim_Tij = [] dim_Lij = [] for fac, exp in tate_factor_Zp(cyc_fac): # the rows of Tij are a basis for Tij # the 'computed' argument avoids echelonizing the kernel basis # which might induce some precision loss on the projection #Tij = fac(frob_matrix).right_kernel_matrix(basis='computed') # computing the right kernel with smith form # howell form or strong echelon could also be good options Tij = padic_right_kernel_matrix(fac(frob_matrix)) if Tij.nrows() != fac.degree() * exp * cyc_exp: raise PrecisionError( "Number of eigenvectors (%d) doesn't match the number of eigenvalues (%d), increasing precision should solve this" % (Tij.nrows(), fac.degree() * exp * cyc_exp)) if over_Qp: dim_Tij.append(Tij.nrows()) obs_map = Tij * P1 rank_obs_ij = obs_map.rank() obsij.append(rank_obs_ij) Lijmatrix = matrix(Tij.base_ring(), Tij.nrows(), 0) for ell in range(fac.degree()): Lijmatrix = Lijmatrix.augment( Tij * frob_power(ell).transpose() * P1) # Lij = right_kernel(K) subspace of Tij that is invariant under Frob and unobstructed Krank = Lijmatrix.rank() dim_Lij.append(Tij.nrows() - Krank) if dim_Lij[-1] % fac.degree() != 0: old_dim = dim_Li[-1] deg = fac.degree() new_dim = dim_Li[-1] = deg * (old_dim // deg) if pedantic: warnings.warn( "rounding dimension of Li from %d to %d for factor = %s" % (old_dim, new_dim, fac)) Ti = Ti.stack(Tij) if over_Qp: dim_Ti.append(dim_Tij) obsi.append(obsij) dim_Li.append(dim_Lij) else: obs_map = Ti * P1 if Ti.nrows() != cyc_fac.degree() * cyc_exp: raise PrecisionError( "Number of eigenvectors (%d) doesn't match the number of eigenvalues (%d), increasing precision should solve this" % (Tij.nrows(), cyc_fac.degree() * cyc_exp)) dim_Ti.append(Ti.nrows()) rank_obs_i = padic_rank(obs_map) obsi.append(Ti.nrows() - rank_obs_i) Limatrix = matrix(Ti.base_ring(), Ti.nrows(), 0) for ell in range(0, cyc_fac.degree()): Limatrix = Limatrix.augment(Ti * frob_power(ell).transpose() * P1) #print(Limatrix.smith_form(exact=False, integral=True, transformation=False).diagonal()) # Li = right_kernel(K) subspace of Tij that is invariant under Frob and unobstructed Krank = padic_rank(Limatrix) dim_Li.append(Ti.nrows() - Krank) if dim_Li[-1] % cyc_fac.degree() != 0: old_dim = dim_Li[-1] deg = cyc_fac.degree() new_dim = dim_Li[-1] = deg * (old_dim // deg) if pedantic: warnings.warn( "rounding dimension of Li from %d to %d for cyc_factor = %s" % (old_dim, new_dim, cyc_fac)) return factor_i, dim_Ti, obsi, dim_Li,
def residue(self, absprec=1, field=None, check_prec=True): r""" Reduces this element modulo `p^{\mathrm{absprec}}`. INPUT: - ``absprec`` -- a non-negative integer (default: ``1``) - ``field`` -- boolean (default ``None``). Whether to return an element of GF(p) or Zmod(p). - ``check_prec`` -- boolean (default ``True``). Whether to raise an error if this element has insufficient precision to determine the reduction. OUTPUT: This element reduced modulo `p^\mathrm{absprec}` as an element of `\ZZ/p^\mathrm{absprec}\ZZ` EXAMPLES:: sage: R = ZpLC(7,4) sage: a = R(8) sage: a.residue(1) 1 TESTS:: sage: R = ZpLC(7,4) sage: a = R(8) sage: a.residue(0) 0 sage: a.residue(-1) Traceback (most recent call last): ... ValueError: cannot reduce modulo a negative power of p. sage: a.residue(5) Traceback (most recent call last): ... PrecisionError: not enough precision known in order to compute residue. sage: a.residue(5, check_prec=False) 8 sage: a.residue(field=True).parent() Finite Field of size 7 """ if not isinstance(absprec, Integer): absprec = Integer(absprec) if check_prec and absprec > self.precision_absolute(): raise PrecisionError( "not enough precision known in order to compute residue.") elif absprec < 0: raise ValueError("cannot reduce modulo a negative power of p.") if self.valuation() < 0: raise ValueError( "element must have non-negative valuation in order to compute residue." ) if field is None: field = (absprec == 1) elif field and absprec != 1: raise ValueError("field keyword may only be set at precision 1") p = self._parent.prime() if field: from sage.rings.finite_rings.finite_field_constructor import GF ring = GF(p) else: from sage.rings.finite_rings.integer_mod_ring import Integers ring = Integers(p**absprec) return ring(self.value())
def factor(self): """ Return the factorization of this polynomial. EXAMPLES:: sage: R.<t> = PolynomialRing(Qp(3,3,print_mode='terse',print_pos=False)) sage: pol = t^8 - 1 sage: for p,e in pol.factor(): ....: print("{} {}".format(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 + (0 + O(3^3))*t + (1 + O(3^3)) sage: R.<t> = 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.<t> = 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.<w> = 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.<T> = 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 _roots(self, secure, minval, hint): """ Return the roots of this polynomial whose valuation is at least ``minval``. This is a helper method for :meth:`roots`. It is not meant to be called directly. INPUT: - ``secure`` -- a boolean; whether we raise an error or not in case of multiple roots - ``minval`` -- an integer - ``hint`` -- a list or ``None``; if given, it must be the list of roots of the residual polynomial of slope ``minval`` OUTPUT: A list of pairs ``(root, multiplicity)`` TESTS:: sage: R = Zp(2) sage: S.<x> = R[] sage: P = (x-1) * (x-2) * (x-4) * (x-8) * (x-16) sage: Q = P^2 sage: Q.roots(algorithm="sage") # indirect doctest [(2^4 + O(2^14), 2), (2^3 + O(2^13), 2), (2^2 + O(2^12), 2), (2 + O(2^11), 2), (1 + O(2^10), 2)] """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing K = self.base_ring() Pk = PolynomialRing(K.residue_field(), names='xbar') x = self.parent().gen() # Trivial cases if self.degree() == 0: return [ ] if self.degree() == 1: return [ (-self[0]/self[1], 1) ] # We consider the case where zero is a (possibly multiple) root i = 0 while self[i] == 0: i += 1 if secure and i > 1: raise PrecisionError("not enough precision to determine the number of roots") if i == 0: roots = [ ] P = self else: vali = self[i].valuation() prec = min((self[j].precision_absolute()-vali) / (i-j) for j in range(i)) if prec is not Infinity: prec = prec.ceil() roots = [ (K(0,prec), i) ] P = self // self[:i+1] # we do not shift because we need to track precision here # We use Newton polygon and slope factorisation to find roots vertices = P.newton_polygon().vertices(copy=False) deg = 0 for i in range(1, len(vertices)): deg_left, val_left = vertices[i-1] deg_right, val_right = vertices[i] slope = (val_right - val_left) / (deg_left - deg_right) if slope not in ZZ or slope < minval: continue if hint is not None and slope == minval: rootsbar = hint if not rootsbar: continue if i < len(vertices) - 1: F = P._factor_of_degree(deg_right - deg) P = P // F else: F = P if deg < deg_left: G = F._factor_of_degree(deg_left - deg) F //= G deg = deg_right val = F[0].valuation() if hint is None or slope != minval: Fbar = Pk([ F[j] >> (val - j*slope) for j in range(F.degree()+1) ]) rootsbar = [ r for (r, _) in Fbar.roots() ] if not rootsbar: continue rbar = rootsbar.pop() shift = K(rbar).lift_to_precision() << slope # probably we should choose a better lift roots += [(r+shift, m) for (r, m) in F(x+shift)._roots(secure, slope, [r-rbar for r in rootsbar])] # recursive call return roots