From f10c1efe1eaf286f5d60b8416b573aded49e1ddd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe <mkoeppe@math.ucdavis.edu> Date: Wed, 19 Apr 2023 18:41:31 -0700 Subject: [PATCH 1/8] sage.rings: Modularization fixes for Laurent polynomials, series --- src/sage/rings/big_oh.py | 32 +- src/sage/rings/laurent_series_ring.py | 6 +- .../rings/polynomial/laurent_polynomial.pxd | 12 - .../rings/polynomial/laurent_polynomial.pyx | 1909 +---------------- .../polynomial/laurent_polynomial_ring.py | 7 +- 5 files changed, 84 insertions(+), 1882 deletions(-) diff --git a/src/sage/rings/big_oh.py b/src/sage/rings/big_oh.py index 64ce5562f2c..1df61a39dc0 100644 --- a/src/sage/rings/big_oh.py +++ b/src/sage/rings/big_oh.py @@ -9,11 +9,24 @@ - `polynomials <../../../polynomial_rings/index.html>`_ """ -import sage.arith.all as arith -from . import laurent_series_ring_element -from sage.rings.puiseux_series_ring_element import PuiseuxSeries -import sage.rings.padics.factory as padics_factory -import sage.rings.padics.padic_generic_element as padic_generic_element +from sage.arith.misc import factor + +try: + from .laurent_series_ring_element import LaurentSeries +except ImportError: + LaurentSeries = () + +try: + from sage.rings.puiseux_series_ring_element import PuiseuxSeries +except ImportError: + PuiseuxSeries = () + +try: + import sage.rings.padics.factory as padics_factory + from sage.rings.padics.padic_generic_element.padic_generic_element import pAdicGenericElement +except ImportError: + pAdicGenericElement = () + from . import power_series_ring_element from . import integer from . import rational @@ -137,9 +150,8 @@ def O(*x, **kwds): "for the maximal ideal (x)") return x.parent().completion(x.parent().gen())(0, x.degree(), **kwds) - elif isinstance(x, laurent_series_ring_element.LaurentSeries): - return laurent_series_ring_element.LaurentSeries(x.parent(), 0).\ - add_bigoh(x.valuation(), **kwds) + elif isinstance(x, LaurentSeries): + return LaurentSeries(x.parent(), 0).add_bigoh(x.valuation(), **kwds) elif isinstance(x, PuiseuxSeries): return x.add_bigoh(x.valuation(), **kwds) @@ -148,7 +160,7 @@ def O(*x, **kwds): # p-adic number if x <= 0: raise ArithmeticError("x must be a prime power >= 2") - F = arith.factor(x) + F = factor(x) if len(F) != 1: raise ArithmeticError("x must be prime power") p, r = F[0] @@ -159,7 +171,7 @@ def O(*x, **kwds): return padics_factory.Qp(p, prec=max(r, 20), type='capped-rel')(0, absprec=r, **kwds) - elif isinstance(x, padic_generic_element.pAdicGenericElement): + elif isinstance(x, pAdicGenericElement): return x.parent()(0, absprec=x.valuation(), **kwds) elif hasattr(x, 'O'): return x.O(**kwds) diff --git a/src/sage/rings/laurent_series_ring.py b/src/sage/rings/laurent_series_ring.py index 56551b50a55..d034b416a50 100644 --- a/src/sage/rings/laurent_series_ring.py +++ b/src/sage/rings/laurent_series_ring.py @@ -47,6 +47,11 @@ from sage.rings.integer_ring import ZZ +try: + from sage.libs.pari.all import pari_gen +except ImportError: + pari_gen = () + def is_LaurentSeriesRing(x): """ @@ -469,7 +474,6 @@ def _element_constructor_(self, x, n=0, prec=infinity): from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.structure.element import parent - from sage.libs.pari.all import pari_gen P = parent(x) if isinstance(x, self.element_class) and n == 0 and P is self: diff --git a/src/sage/rings/polynomial/laurent_polynomial.pxd b/src/sage/rings/polynomial/laurent_polynomial.pxd index cb0a4ab4ea0..3648d6d1ed1 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pxd +++ b/src/sage/rings/polynomial/laurent_polynomial.pxd @@ -1,6 +1,4 @@ from sage.structure.element cimport CommutativeAlgebraElement, ModuleElement, RingElement, Element -from sage.rings.polynomial.polydict cimport ETuple, PolyDict -from sage.rings.polynomial.multi_polynomial cimport MPolynomial cdef class LaurentPolynomial(CommutativeAlgebraElement): @@ -17,13 +15,3 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): cpdef __normalize(self) cpdef _unsafe_mutate(self, i, value) -cdef class LaurentPolynomial_mpair(LaurentPolynomial): - cdef ETuple _mon - cdef MPolynomial _poly - cdef PolyDict _prod - cdef _compute_polydict(self) - cdef _normalize(self, i=*) - cpdef rescale_vars(self, dict d, h=*, new_ring=*) - cpdef toric_coordinate_change(self, M, h=*, new_ring=*) - cpdef toric_substitute(self, v, v1, a, h=*, new_ring=*) - diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index b597397c9e5..0604b0f0111 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -19,7 +19,6 @@ from sage.rings.polynomial.polydict cimport monomial_exponent from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.structure.richcmp cimport richcmp, rich_to_bool -from sage.matrix.matrix0 cimport Matrix cdef class LaurentPolynomial(CommutativeAlgebraElement): """ @@ -179,14 +178,14 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): sage: R.<x> = LaurentPolynomialRing(QQ) sage: a = x^2 + 3*x^3 + 5*x^-1 - sage: a.change_ring(GF(3)) + sage: a.change_ring(GF(3)) # optional - sage.rings.finite_rings 2*x^-1 + x^2 Check that :trac:`22277` is fixed:: sage: R.<x, y> = LaurentPolynomialRing(QQ) sage: a = 2*x^2 + 3*x^3 + 4*x^-1 - sage: a.change_ring(GF(3)) + sage: a.change_ring(GF(3)) # optional - sage.rings.finite_rings -x^2 + x^-1 """ return self._parent.change_ring(R)(self) @@ -255,38 +254,40 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): EXAMPLES:: - sage: k.<a> = GF(9) - sage: R.<x> = LaurentPolynomialRing(k) - sage: f = x*a + a - sage: f.map_coefficients(lambda a : a + 1) + sage: k.<a> = GF(9) # optional - sage.rings.finite_rings + sage: R.<x> = LaurentPolynomialRing(k) # optional - sage.rings.finite_rings + sage: f = x*a + a # optional - sage.rings.finite_rings + sage: f.map_coefficients(lambda a: a + 1) # optional - sage.rings.finite_rings (a + 1) + (a + 1)*x - sage: R.<x,y> = LaurentPolynomialRing(k, 2) - sage: f = x*a + 2*x^3*y*a + a - sage: f.map_coefficients(lambda a : a + 1) + sage: R.<x,y> = LaurentPolynomialRing(k, 2) # optional - sage.rings.finite_rings + sage: f = x*a + 2*x^3*y*a + a # optional - sage.rings.finite_rings + sage: f.map_coefficients(lambda a: a + 1) # optional - sage.rings.finite_rings (2*a + 1)*x^3*y + (a + 1)*x + a + 1 Examples with different base ring:: - sage: R.<r> = GF(9); S.<s> = GF(81) - sage: h = Hom(R,S)[0]; h + sage: R.<r> = GF(9); S.<s> = GF(81) # optional - sage.rings.finite_rings + sage: h = Hom(R, S)[0]; h # optional - sage.rings.finite_rings Ring morphism: From: Finite Field in r of size 3^2 To: Finite Field in s of size 3^4 Defn: r |--> 2*s^3 + 2*s^2 + 1 - sage: T.<X,Y> = LaurentPolynomialRing(R, 2) - sage: f = r*X+Y - sage: g = f.map_coefficients(h); g + sage: T.<X,Y> = LaurentPolynomialRing(R, 2) # optional - sage.rings.finite_rings + sage: f = r*X + Y # optional - sage.rings.finite_rings + sage: g = f.map_coefficients(h); g # optional - sage.rings.finite_rings (2*s^3 + 2*s^2 + 1)*X + Y - sage: g.parent() - Multivariate Laurent Polynomial Ring in X, Y over Finite Field in s of size 3^4 - sage: h = lambda x: x.trace() - sage: g = f.map_coefficients(h); g + sage: g.parent() # optional - sage.rings.finite_rings + Multivariate Laurent Polynomial Ring in X, Y + over Finite Field in s of size 3^4 + sage: h = lambda x: x.trace() # optional - sage.rings.finite_rings + sage: g = f.map_coefficients(h); g # optional - sage.rings.finite_rings X - Y - sage: g.parent() - Multivariate Laurent Polynomial Ring in X, Y over Finite Field in r of size 3^2 - sage: g = f.map_coefficients(h, new_base_ring=GF(3)); g + sage: g.parent() # optional - sage.rings.finite_rings + Multivariate Laurent Polynomial Ring in X, Y + over Finite Field in r of size 3^2 + sage: g = f.map_coefficients(h, new_base_ring=GF(3)); g # optional - sage.rings.finite_rings X - Y - sage: g.parent() + sage: g.parent() # optional - sage.rings.finite_rings Multivariate Laurent Polynomial Ring in X, Y over Finite Field of size 3 """ @@ -331,13 +332,13 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): :: - sage: S.<s> = LaurentPolynomialRing(GF(5)) - sage: T.<t> = PolynomialRing(pAdicRing(5)) - sage: S(t) + sage: S.<s> = LaurentPolynomialRing(GF(5)) # optional - sage.rings.finite_rings sage.rings.padics + sage: T.<t> = PolynomialRing(pAdicRing(5)) # optional - sage.rings.finite_rings sage.rings.padics + sage: S(t) # optional - sage.rings.finite_rings sage.rings.padics s - sage: parent(S(t)) + sage: parent(S(t)) # optional - sage.rings.finite_rings sage.rings.padics Univariate Laurent Polynomial Ring in s over Finite Field of size 5 - sage: parent(S(t)[1]) + sage: parent(S(t)[1]) # optional - sage.rings.finite_rings sage.rings.padics Finite Field of size 5 :: @@ -387,7 +388,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: Pxy = PolynomialRing(QQ, "x,y") sage: Paxb = PolynomialRing(QQ, "a,x,b") sage: Qx = PolynomialRing(ZZ, "x") - sage: Rx = PolynomialRing(GF(2), "x") + sage: Rx = PolynomialRing(GF(2), "x") # optional - sage.rings.finite_rings sage: p1 = Lx.gen() sage: p2 = Lx.zero() sage: p3 = Lx.one() @@ -395,8 +396,10 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: p5 = Lx.gen()**3 + 2*Lx.gen()**2 sage: p6 = Lx.gen() >> 2 - sage: for P,x in [(Px, Px.gen()), (Qx, Qx.gen()), (Rx, Rx.gen()), - ....: (Pxy, Pxy.gen(0)), (Paxb, Paxb.gen(1))]: + sage: Pxes = [(Px, Px.gen()), (Qx, Qx.gen()), + ....: (Pxy, Pxy.gen(0)), (Paxb, Paxb.gen(1))] + sage: Pxes += [(Rx, Rx.gen())] # optional - sage.rings.finite_rings + sage: for P, x in Pxes: ....: assert P(p1) == x and parent(P(p1)) is P ....: assert P(p2) == P.zero() and parent(P(p2)) is P ....: assert P(p3) == P.one() and parent(P(p3)) is P @@ -511,12 +514,12 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): You can specify a map on the base ring:: sage: Zx.<x> = ZZ[] - sage: K.<i> = NumberField(x^2 + 1) - sage: cc = K.hom([-i]) - sage: R.<t> = LaurentPolynomialRing(K) - sage: H = Hom(R, R) - sage: phi = H([t^-2], base_map=cc) - sage: phi(i*t) + sage: K.<i> = NumberField(x^2 + 1) # optional - sage.rings.number_field + sage: cc = K.hom([-i]) # optional - sage.rings.number_field + sage: R.<t> = LaurentPolynomialRing(K) # optional - sage.rings.number_field + sage: H = Hom(R, R) # optional - sage.rings.number_field + sage: phi = H([t^-2], base_map=cc) # optional - sage.rings.number_field + sage: phi(i*t) # optional - sage.rings.number_field -i*t^-2 """ x = im_gens[0] @@ -605,9 +608,9 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): Verify that :trac:`6656` has been fixed:: - sage: R.<a,b>=PolynomialRing(QQ) - sage: T.<x>=LaurentPolynomialRing(R) - sage: y = a*x+b*x + sage: R.<a,b> = PolynomialRing(QQ) + sage: T.<x> = LaurentPolynomialRing(R) + sage: y = a*x + b*x sage: y._latex_() '\\left(a + b\\right)x' sage: latex(y) @@ -813,20 +816,20 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: R.<x> = LaurentPolynomialRing(QQ) sage: f = x^3 + 2/x - sage: g = f._symbolic_(SR); g + sage: g = f._symbolic_(SR); g # optional - sage.symbolic (x^4 + 2)/x - sage: g(x=2) + sage: g(x=2) # optional - sage.symbolic 9 - sage: g = SR(f) - sage: g(x=2) + sage: g = SR(f) # optional - sage.symbolic + sage: g(x=2) # optional - sage.symbolic 9 Since :trac:`24072` the symbolic ring does not accept positive characteristic:: - sage: R.<w> = LaurentPolynomialRing(GF(7)) - sage: SR(2*w^3 + 1) + sage: R.<w> = LaurentPolynomialRing(GF(7)) # optional - sage.rings.finite_rings + sage: SR(2*w^3 + 1) # optional - sage.rings.finite_rings sage.symbolic Traceback (most recent call last): ... TypeError: positive characteristic not allowed in symbolic computations @@ -1046,10 +1049,10 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ EXAMPLES:: - sage: R.<x> = LaurentPolynomialRing(GF(2)) - sage: f = 1/x^3 + x + x^2 + 3*x^4 - sage: g = 1 - x + x^2 - x^4 - sage: f*g + sage: R.<x> = LaurentPolynomialRing(GF(2)) # optional - sage.rings.finite_rings + sage: f = 1/x^3 + x + x^2 + 3*x^4 # optional - sage.rings.finite_rings + sage: g = 1 - x + x^2 - x^4 # optional - sage.rings.finite_rings + sage: f*g # optional - sage.rings.finite_rings x^-3 + x^-2 + x^-1 + x^8 """ cdef LaurentPolynomial_univariate right = <LaurentPolynomial_univariate>right_r @@ -1961,1809 +1964,3 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): 0 """ return self.__u[-self.__n] - - -cdef class LaurentPolynomial_mpair(LaurentPolynomial): - """ - Multivariate Laurent polynomials. - """ - def __init__(self, parent, x, mon=None, reduce=True): - """ - Currently, one can only create LaurentPolynomials out of dictionaries - and elements of the base ring. - - INPUT: - - - ``parent`` -- a SageMath parent - - - ``x`` -- an element or dictionary or anything the underlying - polynomial ring accepts - - - ``mon`` -- (default: ``None``) a tuple specifying the shift - in the exponents - - - ``reduce`` -- (default: ``True``) a boolean - - EXAMPLES:: - - sage: L.<w,z> = LaurentPolynomialRing(QQ) - sage: f = L({(-1,-1):1}); f - w^-1*z^-1 - sage: f = L({(1,1):1}); f - w*z - sage: f = L({(-1,-1):1, (1,3):4}); f - 4*w*z^3 + w^-1*z^-1 - sage: L(1/2) - 1/2 - - TESTS: - - Check that :trac:`19538` is fixed:: - - sage: R = LaurentPolynomialRing(QQ,'x2,x0') - sage: S = LaurentPolynomialRing(QQ,'x',3) - sage: f = S.coerce_map_from(R) - sage: f(R.gen(0) + R.gen(1)^2) - x0^2 + x2 - sage: _.parent() - Multivariate Laurent Polynomial Ring in x0, x1, x2 over Rational Field - - :: - - sage: from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial_mpair - sage: LaurentPolynomial_mpair(L, {(1,2): 1/42}, mon=(-3, -3)) - 1/42*w^-2*z^-1 - - :trac:`22398`:: - - sage: LQ = LaurentPolynomialRing(QQ, 'x0, x1, x2, y0, y1, y2, y3, y4, y5') - sage: LZ = LaurentPolynomialRing(ZZ, 'x0, x1, x2, y0, y1, y2, y3, y4, y5') - sage: LQ.inject_variables() - Defining x0, x1, x2, y0, y1, y2, y3, y4, y5 - sage: x2^-1*y0*y1*y2*y3*y4*y5 + x1^-1*x2^-1*y0*y1*y3*y4 + x0^-1 in LZ - True - sage: x2^-1*y0*y1*y2*y3*y4*y5 + x1^-1*x2^-1*y0*y1*y3*y4 + x0^-1*x1^-1*y0*y3 + x0^-1 in LZ - True - - Check that input is not modified:: - - sage: LQ.<x,y> = LaurentPolynomialRing(QQ) - sage: D = {(-1, 1): 1} - sage: k = tuple(D)[0] - sage: v = D[k] - sage: type(k), type(v) - (<... 'tuple'>, <class 'sage.rings.integer.Integer'>) - sage: LQ(D) - x^-1*y - sage: tuple(D)[0] is k - True - sage: D[k] is v - True - """ - if isinstance(x, PolyDict): - x = x.dict() - if mon is not None: - if isinstance(mon, ETuple): - self._mon = mon - else: - self._mon = ETuple(mon) - else: - if isinstance(x, dict): - self._mon = ETuple({}, int(parent.ngens())) - D = {} - for k, x_k in x.iteritems(): # ETuple-ize keys, set _mon - if not isinstance(k, (tuple, ETuple)) or len(k) != parent.ngens(): - self._mon = ETuple({}, int(parent.ngens())) - break - if isinstance(k, tuple): - k = ETuple(k) - D[k] = x_k - self._mon = self._mon.emin(k) # point-wise min of _mon and k - else: - x = D - if not self._mon.is_constant(): # factor out _mon - x = {k.esub(self._mon): x_k for k, x_k in x.iteritems()} - elif (isinstance(x, LaurentPolynomial_mpair) and - parent.variable_names() == x.parent().variable_names()): - self._mon = (<LaurentPolynomial_mpair>x)._mon - x = (<LaurentPolynomial_mpair>x)._poly - else: # since x should coerce into parent, _mon should be (0,...,0) - self._mon = ETuple({}, int(parent.ngens())) - self._poly = parent._R(x) - CommutativeAlgebraElement.__init__(self, parent) - - def __reduce__(self): - """ - TESTS:: - - sage: R = LaurentPolynomialRing(QQ,2,'x') - sage: R.<x1,x2> = LaurentPolynomialRing(QQ) - sage: loads(dumps(x1)) == x1 # indirect doctest - True - sage: z = x1/x2 - sage: loads(dumps(z)) == z - True - """ - return self._parent, (self._poly, self._mon) - - def __hash__(self): - r""" - TESTS: - - Test that the hash is non-constant (see also :trac:`27914`):: - - sage: L.<w,z> = LaurentPolynomialRing(QQ) - sage: len({hash(w^i*z^j) for i in [-2..2] for j in [-2..2]}) - 25 - - Check that :trac:`20490` is fixed:: - - sage: R.<a,b> = LaurentPolynomialRing(ZZ) - sage: p = a*~a - sage: p._fraction_pair() - (a, a) - sage: p == R.one() - True - sage: hash(p) - 1 - - Check that :trac:`23864` is fixed (compatibility with integers, rationals - and polynomial rings):: - - sage: L = LaurentPolynomialRing(QQ, 'x0,x1,x2') - sage: hash(L.zero()) - 0 - sage: hash(L.one()) - 1 - sage: hash(-L.one()) - -2 - sage: hash(L(1/2)) == hash(1/2) - True - - sage: R = PolynomialRing(QQ, 'x0,x1,x2') - sage: x0,x1,x2 = R.gens() - sage: hash(x0) == hash(L(x0)) - True - sage: hash(1 - 7*x0 + x1*x2) == hash(L(1 - 7*x0 + x1*x2)) - True - - Check that :trac:`27914` is fixed:: - - sage: L.<w,z> = LaurentPolynomialRing(QQ) - sage: Lw = LaurentPolynomialRing(QQ, 'w') - sage: Lz = LaurentPolynomialRing(QQ, 'z') - sage: all(hash(w^k) == hash(Lw(w^k)) - ....: and hash(z^k) == hash(Lz(z^k)) for k in (-5..5)) - True - sage: p = w^-1 + 2 + w - sage: hash(p) == hash(Lw(p)) - True - """ - # we reimplement the hash from multipolynomial to handle negative exponents - # (see multi_polynomial.pyx) - cdef long result = 0 - cdef long exponent - cdef list var_name_hash = [hash(v) for v in self._parent.variable_names()] - cdef int p - cdef int n = len(var_name_hash) - cdef long c_hash - for m, c in self._poly.iterator_exp_coeff(): - c_hash = hash(c) - if c_hash != 0: - for p in range(n): - exponent = m[p] + self._mon[p] - if exponent > 0: - c_hash = (1000003 * c_hash) ^ var_name_hash[p] - c_hash = (1000003 * c_hash) ^ exponent - elif exponent < 0: - c_hash = (1000003 * c_hash) ^ var_name_hash[p] - c_hash = (700005 * c_hash) ^ exponent - result += c_hash - - return result - - def _im_gens_(self, codomain, im_gens, base_map=None): - """ - Return the image of ``self`` under the morphism defined by - ``im_gens`` in ``codomain``. - - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(ZZ) - sage: M.<u,v> = LaurentPolynomialRing(ZZ) - sage: phi = L.hom([u,v]) - sage: phi(x^2*~y -5*y**3) # indirect doctest - -5*v^3 + u^2*v^-1 - - TESTS: - - check compatibility with :trac:`26105`:: - - sage: F.<t> = GF(4) - sage: LF.<a,b> = LaurentPolynomialRing(F) - sage: rho = LF.hom([b,a], base_map=F.frobenius_endomorphism()) - sage: s = t*~a + b +~t*(b**-3)*a**2; rs = rho(s); rs - a + (t + 1)*b^-1 + t*a^-3*b^2 - sage: s == rho(rs) - True - """ - p = self._poly - m = self._mon - if base_map is not None: - p = p.map_coefficients(base_map) - from sage.misc.misc_c import prod - return codomain(p(im_gens) * prod(ig**m[im_gens.index(ig)] for ig in im_gens)) - - cdef _normalize(self, i=None): - r""" - Remove the common monomials from ``self._poly`` and store - them in ``self._mon``. - - INPUT: - - - ``i`` -- an integer - - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ) - sage: f = x*y + 2*y*x^2 + y # indirect doctest - sage: f.factor() # Notice the y has been factored out. - (y) * (2*x^2 + x + 1) - - Check that :trac:`23864` has been fixed:: - - sage: hash(L.zero()) - 0 - """ - if not self._poly: - self._mon = ETuple({}, int(self._parent.ngens())) - return - - #cdef dict D = <dict> self._poly._mpoly_dict_recursive( - # <tuple> self._parent.variable_names(), - # self._parent.base_ring() - # ) - cdef dict D = <dict> self._poly.dict() - - cdef ETuple e - if i is None: - e = None - for k in D: - if e is None: - e = <ETuple> k - else: - e = e.emin(k) - if not e.is_constant(): - self._poly = <ModuleElement> (self._poly // self._poly._parent({e: 1})) - self._mon = self._mon.eadd(e) - else: - e = None - for k in D: - if e is None or k[i] < e: - e = <ETuple> k[i] - if e > 0: - self._poly = <ModuleElement> (self._poly // self._poly._parent.gen(i)) - self._mon = self._mon.eadd_p(e, i) - - cdef _compute_polydict(self): - """ - EXAMPLES:: - - sage: L.<w,z> = LaurentPolynomialRing(QQ) - sage: a = w^2*z^-1 +3 - sage: a.dict() # indirect doctest - {(0, 0): 3, (2, -1): 1} - """ - #cdef dict D = <dict> self._poly._mpoly_dict_recursive(self._parent.variable_names(), - # self._parent.base_ring()) - cdef dict D = <dict> self._poly.dict() - cdef dict DD - if self._mon.is_constant(): - self._prod = PolyDict(D) - return - DD = {} - for k in D: - DD[k.eadd(self._mon)] = D[k] - self._prod = PolyDict(DD) - - def is_unit(self): - """ - Return ``True`` if ``self`` is a unit. - - The ground ring is assumed to be an integral domain. - - This means that the Laurent polynomial is a monomial - with unit coefficient. - - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ) - sage: (x*y/2).is_unit() - True - sage: (x + y).is_unit() - False - sage: (L.zero()).is_unit() - False - sage: (L.one()).is_unit() - True - - sage: L.<x,y> = LaurentPolynomialRing(ZZ) - sage: (2*x*y).is_unit() - False - """ - coeffs = self.coefficients() - if len(coeffs) != 1: - return False - return coeffs[0].is_unit() - - def _repr_(self): - """ - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ) - sage: f = x^2 + x*y/2 + 2*y^-1 - sage: f._repr_() - 'x^2 + 1/2*x*y + 2*y^-1' - """ - if self._prod is None: - self._compute_polydict() - try: - key = self.parent().term_order().sortkey - except AttributeError: - key = None - atomic = self.parent().base_ring()._repr_option('element_is_atomic') - return self._prod.poly_repr(self.parent().variable_names(), - atomic_coefficients=atomic, sortkey=key) - - def _latex_(self): - r""" - EXAMPLES:: - - sage: L.<w,z> = LaurentPolynomialRing(QQ) - sage: a = w^2*z^-1+3; a - w^2*z^-1 + 3 - sage: latex(a) - w^{2} z^{-1} + 3 - - TESTS:: - - sage: L.<lambda2, y2> = LaurentPolynomialRing(QQ) - sage: latex(1/lambda2 + y2^(-3)) - \lambda_{2}^{-1} + y_{2}^{-3} - """ - if self._prod is None: - self._compute_polydict() - try: - key = self.parent().term_order().sortkey - except AttributeError: - key = None - atomic = self.parent().base_ring()._repr_option('element_is_atomic') - return self._prod.latex(self.parent().latex_variable_names(), - atomic_coefficients=atomic, sortkey=key) - - cpdef long number_of_terms(self) except -1: - """ - Return the number of non-zero coefficients of ``self``. - - Also called weight, hamming weight or sparsity. - - EXAMPLES:: - - sage: R.<x, y> = LaurentPolynomialRing(ZZ) - sage: f = x^3 - y - sage: f.number_of_terms() - 2 - sage: R(0).number_of_terms() - 0 - sage: f = (x+1/y)^100 - sage: f.number_of_terms() - 101 - - The method :meth:`hamming_weight` is an alias:: - - sage: f.hamming_weight() - 101 - """ - return self._poly.number_of_terms() - - def __invert__(LaurentPolynomial_mpair self): - """ - Return the inverse of ``self``. - - This treats monomials specially so they remain Laurent - polynomials; the inverse of any other polynomial is an element - of the rational function field. - - TESTS:: - - sage: L.<x,y> = LaurentPolynomialRing(ZZ) - sage: f = ~x - sage: parent(f) - Multivariate Laurent Polynomial Ring in x, y over Integer Ring - sage: parent(f.coefficients()[0]) is parent(f).base_ring() - True - sage: g = ~(2*x) - sage: parent(g) - Multivariate Laurent Polynomial Ring in x, y over Rational Field - sage: parent(g.coefficients()[0]) is parent(g).base_ring() - True - """ - cdef ETuple e - if self._poly.is_term(): - (e, c), = self.dict().items() - e = e.emul(-1) - P = self._parent - try: - c = c.inverse_of_unit() - except (AttributeError, ZeroDivisionError, ArithmeticError): - c = ~c - if c.parent() is not P.base_ring(): - P = P.change_ring(c.parent()) - return P({e: c}) - return super().__invert__() - - def __pow__(LaurentPolynomial_mpair self, n, m): - """ - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ) - sage: f = x + y - sage: f^2 - x^2 + 2*x*y + y^2 - sage: f^(-1) - 1/(x + y) - - TESTS: - - Check that :trac:`2952` is fixed:: - - sage: R.<q> = QQ[] - sage: L.<x,y,z> = LaurentPolynomialRing(R) - sage: f = (x+y+z^-1)^2 - sage: f.substitute(z=1) - x^2 + 2*x*y + y^2 + 2*x + 2*y + 1 - """ - cdef LaurentPolynomial_mpair ans - if n < 0: - return ~(self ** -n) - ans = self._new_c() - ans._poly = self._poly ** n - ans._mon = self._mon.emul(n) - return ans - - def __getitem__(self, n): - r""" - Return the coefficient of `x^n = x_1^{n_1} \cdots x_k^{n_k}` where - `n` is a tuple of length `k` and `k` is the number of variables. - - If the number of inputs is not equal to the number of variables, this - raises a ``TypeError``. - - EXAMPLES:: - - sage: P.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 + x*z; f - -x^6 + x*z - 7*x^-2*y^3 + 5*x^-2*y + x^-3*y^2 - sage: f[6,0,0] - -1 - sage: f[-2,3,0] - -7 - sage: f[-1,4,2] - 0 - sage: f[1,0,1] - 1 - sage: f[6] - Traceback (most recent call last): - ... - TypeError: must have exactly 3 inputs - sage: f[6,0] - Traceback (most recent call last): - ... - TypeError: must have exactly 3 inputs - sage: f[6,0,0,0] - Traceback (most recent call last): - ... - TypeError: must have exactly 3 inputs - """ - if isinstance(n, slice): - raise TypeError("multivariate Laurent polynomials are not iterable") - if not isinstance(n, tuple) or len(n) != self._parent.ngens(): - raise TypeError("must have exactly %s inputs" % - self.parent().ngens()) - cdef ETuple t = ETuple(n) - if self._prod is None: - self._compute_polydict() - try: - return self._prod[t] - except KeyError: - return self._parent.base_ring().zero() - - def __iter__(self): - """ - Iterate through all terms by returning a list of the coefficient and - the corresponding monomial. - - EXAMPLES:: - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 - sage: sorted(f) # indirect doctest - [(-7, x^-2*y^3), (-1, x^6), (1, x^-3*y^2), (5, x^-2*y)] - """ - P = self._parent - one = P._R.one() - if self._mon.is_constant(): - for exp, coeff in self._poly.iterator_exp_coeff(): - yield (coeff, P.element_class(P, one, exp)) - else: - for exp, coeff in self._poly.iterator_exp_coeff(): - yield (coeff, P.element_class(P, one, exp.eadd(self._mon))) - - def iterator_exp_coeff(self): - """ - Iterate over ``self`` as pairs of (ETuple, coefficient). - - EXAMPLES:: - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 - sage: list(f.iterator_exp_coeff()) - [((6, 0), -1), ((-2, 3), -7), ((-2, 1), 5), ((-3, 2), 1)] - """ - for exp, coeff in self._poly.iterator_exp_coeff(): - yield (exp.eadd(self._mon), coeff) - - def monomials(self): - """ - Return the list of monomials in ``self``. - - EXAMPLES:: - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 - sage: sorted(f.monomials()) - [x^-3*y^2, x^-2*y, x^-2*y^3, x^6] - """ - return [mon for coeff, mon in self] - - def monomial_coefficient(self, mon): - """ - Return the coefficient in the base ring of the monomial ``mon`` in - ``self``, where ``mon`` must have the same parent as ``self``. - - This function contrasts with the function :meth:`coefficient()` - which returns the coefficient of a monomial viewing this - polynomial in a polynomial ring over a base ring having fewer - variables. - - INPUT: - - - ``mon`` -- a monomial - - .. SEEALSO:: - - For coefficients in a base ring of fewer variables, see - :meth:`coefficient()`. - - EXAMPLES:: - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 - sage: f.monomial_coefficient(x^-2*y^3) - -7 - sage: f.monomial_coefficient(x^2) - 0 - - TESTS:: - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - sage: f = y^2 * x^-2 - sage: f.monomial_coefficient(x + y) - Traceback (most recent call last): - ... - ValueError: not a monomial - """ - if parent(mon) != self._parent: - raise TypeError("input must have the same parent") - cdef LaurentPolynomial_mpair m = <LaurentPolynomial_mpair> mon - if m._prod is None: - m._compute_polydict() - if self._prod is None: - self._compute_polydict() - exp = monomial_exponent(m._prod) - zero = self._parent.base_ring().zero() - return self._prod.get(exp, zero) - - def constant_coefficient(self): - """ - Return the constant coefficient of ``self``. - - EXAMPLES:: - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - sage: f = (y^2 - x^9 - 7*x*y^2 + 5*x*y)*x^-3; f - -x^6 - 7*x^-2*y^2 + 5*x^-2*y + x^-3*y^2 - sage: f.constant_coefficient() - 0 - sage: f = (x^3 + 2*x^-2*y+y^3)*y^-3; f - x^3*y^-3 + 1 + 2*x^-2*y^-2 - sage: f.constant_coefficient() - 1 - """ - return self[(0,)*self._parent.ngens()] - - def coefficient(self, mon): - r""" - Return the coefficient of ``mon`` in ``self``, where ``mon`` must - have the same parent as ``self``. - - The coefficient is defined as follows. If `f` is this polynomial, then - the coefficient `c_m` is sum: - - .. MATH:: - - c_m := \sum_T \frac{T}{m} - - where the sum is over terms `T` in `f` that are exactly divisible - by `m`. - - A monomial `m(x,y)` 'exactly divides' `f(x,y)` if `m(x,y) | f(x,y)` - and neither `x \cdot m(x,y)` nor `y \cdot m(x,y)` divides `f(x,y)`. - - INPUT: - - - ``mon`` -- a monomial - - OUTPUT: - - Element of the parent of ``self``. - - .. NOTE:: - - To get the constant coefficient, call - :meth:`constant_coefficient()`. - - EXAMPLES:: - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - - The coefficient returned is an element of the parent of ``self``; in - this case, ``P``. :: - - sage: f = 2 * x * y - sage: c = f.coefficient(x*y); c - 2 - sage: c.parent() - Multivariate Laurent Polynomial Ring in x, y over Rational Field - - sage: P.<x,y> = LaurentPolynomialRing(QQ) - sage: f = (y^2 - x^9 - 7*x*y^2 + 5*x*y)*x^-3; f - -x^6 - 7*x^-2*y^2 + 5*x^-2*y + x^-3*y^2 - sage: f.coefficient(y) - 5*x^-2 - sage: f.coefficient(y^2) - -7*x^-2 + x^-3 - sage: f.coefficient(x*y) - 0 - sage: f.coefficient(x^-2) - -7*y^2 + 5*y - sage: f.coefficient(x^-2*y^2) - -7 - sage: f.coefficient(1) - -x^6 - 7*x^-2*y^2 + 5*x^-2*y + x^-3*y^2 - """ - if mon.parent() is not self._parent: - mon = self._parent(mon) - cdef LaurentPolynomial_mpair m = <LaurentPolynomial_mpair> mon - if self._prod is None: - self._compute_polydict() - if m._prod is None: - m._compute_polydict() - return self._parent(self._prod.coefficient(m.dict())) - - def coefficients(self): - """ - Return the nonzero coefficients of ``self`` in a list. - - The returned list is decreasingly ordered by the term ordering - of ``self.parent()``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ,order='degrevlex') - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f.coefficients() - [4, 3, 2, 1] - sage: L.<x,y,z> = LaurentPolynomialRing(QQ,order='lex') - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f.coefficients() - [4, 1, 2, 3] - """ - return self._poly.coefficients() - - def variables(self, sort=True): - """ - Return a tuple of all variables occurring in ``self``. - - INPUT: - - - ``sort`` -- specifies whether the indices shall be sorted - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f.variables() - (z, y, x) - sage: f.variables(sort=False) #random - (y, z, x) - """ - cdef dict d = self.dict() - cdef tuple g = self._parent.gens() - cdef Py_ssize_t nvars = len(g) - cdef set vars = set() - for k in d: - vars.update(k.nonzero_positions()) - if len(vars) == nvars: - break - cdef list v = [g[i] for i in vars] - if sort: - v.sort() - return tuple(v) - - cpdef dict dict(self): - """ - Return ``self`` represented as a ``dict``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: sorted(f.dict().items()) - [((3, 1, 0), 3), ((4, 0, -2), 2), ((6, -7, 0), 1), ((7, 0, -1), 4)] - """ - if self._prod is None: - self._compute_polydict() - return <dict> self._prod.dict() - - def _fraction_pair(self): - """ - Return one representation of ``self`` as a pair - ``(numerator, denominator)``. - - Here both the numerator and the denominator are polynomials. - - This is used for coercion into the fraction field. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f._fraction_pair() - (4*x^7*y^7*z + 3*x^3*y^8*z^2 + 2*x^4*y^7 + x^6*z^2, y^7*z^2) - """ - ring = self._parent._R - numer = self._poly - denom = ring.one() - var = ring.gens() - for i, j in enumerate(self._mon): - if j > 0: - numer *= var[i] ** j - else: - denom *= var[i] ** (-j) - return (numer, denom) - - cpdef _add_(self, _right): - """ - Return the Laurent polynomial ``self + right``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + y^-1 - sage: g = y + z - sage: f + g - x + y + z + y^-1 - """ - cdef LaurentPolynomial_mpair ans = self._new_c() - cdef LaurentPolynomial_mpair right = <LaurentPolynomial_mpair>_right - ans._mon, a, b = self._mon.combine_to_positives(right._mon) - if not a.is_constant(): - ans._poly = self._poly * self._poly._parent({a: 1}) - else: - ans._poly = self._poly - if not b.is_constant(): - ans._poly += right._poly * self._poly._parent({b: 1}) - else: - ans._poly += right._poly - return ans - - cpdef _sub_(self, _right): - """ - Return the Laurent polynomial ``self - right``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + y^-1 - sage: g = y + z + x - sage: f - g - -y - z + y^-1 - """ - cdef LaurentPolynomial_mpair ans = self._new_c() - cdef LaurentPolynomial_mpair right = <LaurentPolynomial_mpair>_right - cdef ETuple a, b - ans._mon, a, b = self._mon.combine_to_positives(right._mon) - if not a.is_constant(): - ans._poly = self._poly * self._poly._parent({a: 1}) - else: - ans._poly = self._poly - if not b.is_constant(): - ans._poly -= right._poly * self._poly._parent({b: 1}) - else: - ans._poly -= right._poly - return ans - - cpdef _div_(self, rhs): - """ - Return the division of ``self`` by ``rhs``. - - If the denominator is not a unit, - the result will be given in the fraction field. - - EXAMPLES:: - - sage: R.<s,q,t> = LaurentPolynomialRing(QQ) - sage: 1/s - s^-1 - sage: 1/(s*q) - s^-1*q^-1 - sage: 1/(s+q) - 1/(s + q) - sage: (1/(s+q)).parent() - Fraction Field of Multivariate Polynomial Ring in s, q, t over Rational Field - sage: (1/(s*q)).parent() - Multivariate Laurent Polynomial Ring in s, q, t over Rational Field - sage: (s+q)/(q^2*t^(-2)) - s*q^-2*t^2 + q^-1*t^2 - """ - cdef LaurentPolynomial_mpair right = <LaurentPolynomial_mpair> rhs - if right.is_zero(): - raise ZeroDivisionError - if right._poly.is_term(): - return self * ~right - else: - return RingElement._div_(self, rhs) - - def is_monomial(self): - """ - Return ``True`` if ``self`` is a monomial. - - EXAMPLES:: - - sage: k.<y,z> = LaurentPolynomialRing(QQ) - sage: z.is_monomial() - True - sage: k(1).is_monomial() - True - sage: (z+1).is_monomial() - False - sage: (z^-2909).is_monomial() - True - sage: (38*z^-2909).is_monomial() - False - """ - return self._poly.is_monomial() - - cpdef _neg_(self): - """ - Return ``-self``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + y^-1 - sage: -f - -x - y^-1 - """ - cdef LaurentPolynomial_mpair ans = self._new_c() - ans._mon = self._mon - ans._poly = -self._poly - return ans - - cpdef _lmul_(self, Element right): - """ - Return ``self * right`` where ``right`` is in ``self``'s base ring. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + y^-1 - sage: f*(1/2) - 1/2*x + 1/2*y^-1 - """ - cdef LaurentPolynomial_mpair ans = self._new_c() - ans._mon = self._mon - ans._poly = self._poly * right - return ans - - cpdef _rmul_(self, Element left): - """ - Return ``left * self`` where ``left`` is in ``self``'s base ring. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + y^-1 - sage: (1/2)*f - 1/2*x + 1/2*y^-1 - """ - cdef LaurentPolynomial_mpair ans = self._new_c() - ans._mon = self._mon - ans._poly = left * self._poly - return ans - - cpdef _mul_(self, right): - """ - Return ``self * right``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + y^-1 - sage: g = y + z - sage: f*g - x*y + x*z + 1 + y^-1*z - """ - cdef LaurentPolynomial_mpair ans = self._new_c() - ans._mon = self._mon.eadd((<LaurentPolynomial_mpair>right)._mon) - ans._poly = self._poly * (<LaurentPolynomial_mpair>right)._poly - return ans - - cpdef _floordiv_(self, right): - """ - Perform division with remainder and return the quotient. - - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ) - sage: f = x^3 + y^-3 - sage: g = y + x - sage: f // g - x^5*y^-3 - x^4*y^-2 + x^3*y^-1 - - sage: h = x + y^(-1) - sage: f // h - x^2 - x*y^-1 + y^-2 - sage: h * (f // h) == f - True - sage: f // 1 - x^3 + y^-3 - sage: 1 // f - 0 - - TESTS: - - Check that :trac:`19357` is fixed:: - - sage: x // y - x*y^-1 - - Check that :trac:`21999` is fixed:: - - sage: L.<a,b> = LaurentPolynomialRing(QQbar) - sage: (a+a*b) // a - b + 1 - """ - cdef LaurentPolynomial_mpair ans = self._new_c() - cdef LaurentPolynomial_mpair rightl = <LaurentPolynomial_mpair> right - self._normalize() - rightl._normalize() - ans._mon = self._mon.esub(rightl._mon) - ans._poly = self._poly // rightl._poly - return ans - - @coerce_binop - def quo_rem(self, right): - """ - Divide this Laurent polynomial by ``right`` and return a quotient and - a remainder. - - INPUT: - - - ``right`` -- a Laurent polynomial - - OUTPUT: - - A pair of Laurent polynomials. - - EXAMPLES:: - - sage: R.<s, t> = LaurentPolynomialRing(QQ) - sage: (s^2-t^2).quo_rem(s-t) - (s + t, 0) - sage: (s^-2-t^2).quo_rem(s-t) - (s + t, -s^2 + s^-2) - sage: (s^-2-t^2).quo_rem(s^-1-t) - (t + s^-1, 0) - - TESTS: - - Verify that :trac:`31257` is fixed:: - - sage: R.<x,y> = LaurentPolynomialRing(QQ) - sage: q, r = (1/x).quo_rem(y) - sage: q, r - (x^-1*y^-1, 0) - sage: q*y + r == 1/x - True - sage: q,r = (x^-2 - y^2).quo_rem(x - y) - sage: q*(x - y) + r == x^-2 - y^2 - True - """ - # make copies of self and right so that the input can be normalized - # without affecting the objects that were passed to the method - cdef LaurentPolynomial_mpair selfl = self._new_c() - selfl._poly = self._poly - selfl._mon = self._mon - cdef LaurentPolynomial_mpair rightl = self._new_c() - rightl._poly = (<LaurentPolynomial_mpair> right)._poly - rightl._mon = (<LaurentPolynomial_mpair> right)._mon - - selfl._normalize() - rightl._normalize() - q, r = selfl._poly.quo_rem(rightl._poly) - ql = LaurentPolynomial_mpair(self._parent, q, - mon=selfl._mon.esub(rightl._mon)) - rl = LaurentPolynomial_mpair(self._parent, r, - mon=selfl._mon) - ql._normalize() - rl._normalize() - return (ql, rl) - - cpdef _richcmp_(self, right, int op): - """ - Compare two polynomials in a `LaurentPolynomialRing` based on the term - order from the parent ring. If the parent ring does not specify a term - order then only comparison by equality is supported. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + y^-1 - sage: g = y + z - sage: f == f - True - sage: f == g - False - sage: f == 2 - False - """ - if self._prod is None: - self._compute_polydict() - if (<LaurentPolynomial_mpair> right)._prod is None: - (<LaurentPolynomial_mpair> right)._compute_polydict() - - try: - sortkey = self._parent.term_order().sortkey - except AttributeError: - sortkey = None - - return self._prod.rich_compare((<LaurentPolynomial_mpair>right)._prod, - op, sortkey) - - def exponents(self): - """ - Return a list of the exponents of ``self``. - - EXAMPLES:: - - sage: L.<w,z> = LaurentPolynomialRing(QQ) - sage: a = w^2*z^-1+3; a - w^2*z^-1 + 3 - sage: e = a.exponents() - sage: e.sort(); e - [(0, 0), (2, -1)] - - """ - return [a.eadd(self._mon) for a in self._poly.exponents()] - - def degree(self, x=None): - """ - Return the degree of ``x`` in ``self``. - - EXAMPLES:: - - sage: R.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f.degree(x) - 7 - sage: f.degree(y) - 1 - sage: f.degree(z) - 0 - """ - if not x: - return self._poly.total_degree() + sum(self._mon) - - cdef tuple g = <tuple> self._parent.gens() - cdef Py_ssize_t i - cdef bint no_generator_found = True - for i in range(len(g)): - if g[i] is x: - no_generator_found = False - break - if no_generator_found: - raise TypeError("x must be a generator of parent") - return self._poly.degree(self._parent._R.gens()[i]) + self._mon[i] - - def has_inverse_of(self, i): - """ - INPUT: - - - ``i`` -- The index of a generator of ``self.parent()`` - - OUTPUT: - - Returns True if self contains a monomial including the inverse of - ``self.parent().gen(i)``, False otherwise. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f.has_inverse_of(0) - False - sage: f.has_inverse_of(1) - True - sage: f.has_inverse_of(2) - True - """ - if (not isinstance(i, (int, Integer))) or (i < 0) or (i >= self._parent.ngens()): - raise TypeError("argument is not the index of a generator") - if self._mon[i] < 0: - self._normalize(i) - if self._mon[i] < 0: - return True - return False - return False - - def has_any_inverse(self): - """ - Returns True if self contains any monomials with a negative exponent, False otherwise. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f.has_any_inverse() - True - sage: g = x^2 + y^2 - sage: g.has_any_inverse() - False - """ - for m in self._mon.nonzero_values(sort=False): - if m < 0: - return True - return False - - def __call__(self, *x, **kwds): - """ - Compute value of ``self`` at ``x``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = x + 2*y + 3*z - sage: f(1,1,1) - 6 - sage: f = x^-1 + y + z - sage: f(0,1,1) - Traceback (most recent call last): - ... - ZeroDivisionError - - TESTS:: - - sage: f = x + 2*y + 3*z - sage: f(2) - Traceback (most recent call last): - ... - TypeError: number of arguments does not match the number of generators in parent - sage: f(2,0) - Traceback (most recent call last): - ... - TypeError: number of arguments does not match the number of generators in parent - sage: f( (1,1,1) ) - 6 - """ - if kwds: - f = self.subs(**kwds) - if x: # More than 1 non-keyword argument - return f(*x) - else: - return f - - cdef int l = len(x) - - if l == 1 and isinstance(x[0], (tuple, list)): - x = x[0] - l = len(x) - - if l != self._parent.ngens(): - raise TypeError("number of arguments does not match the number" - " of generators in parent") - - #Check to make sure that we aren't dividing by zero - cdef Py_ssize_t m - for m in range(l): - if x[m] == 0: - if self.has_inverse_of(m): - raise ZeroDivisionError - - ans = self._poly(*x) - if ans: - for m in self._mon.nonzero_positions(): - ans *= x[m]**self._mon[m] - - return ans - - def subs(self, in_dict=None, **kwds): - """ - Substitute some variables in this Laurent polynomial. - - Variable/value pairs for the substitution may be given - as a dictionary or via keyword-value pairs. If both are - present, the latter take precedence. - - INPUT: - - - ``in_dict`` -- dictionary (optional) - - - ``**kwargs`` -- keyword arguments - - OUTPUT: - - A Laurent polynomial. - - EXAMPLES:: - - sage: L.<x, y, z> = LaurentPolynomialRing(QQ) - sage: f = x + 2*y + 3*z - sage: f.subs(x=1) - 2*y + 3*z + 1 - sage: f.subs(y=1) - x + 3*z + 2 - sage: f.subs(z=1) - x + 2*y + 3 - sage: f.subs(x=1, y=1, z=1) - 6 - - sage: f = x^-1 - sage: f.subs(x=2) - 1/2 - sage: f.subs({x: 2}) - 1/2 - - sage: f = x + 2*y + 3*z - sage: f.subs({x: 1, y: 1, z: 1}) - 6 - sage: f.substitute(x=1, y=1, z=1) - 6 - - TESTS:: - - sage: f = x + 2*y + 3*z - sage: f(q=10) - x + 2*y + 3*z - - sage: x.subs({x: 2}, x=1) - 1 - """ - cdef list variables = list(self._parent.gens()) - cdef Py_ssize_t i - for i in range(len(variables)): - if str(variables[i]) in kwds: - variables[i] = kwds[str(variables[i])] - elif in_dict and variables[i] in in_dict: - variables[i] = in_dict[variables[i]] - return self(tuple(variables)) - - def is_constant(self): - r""" - Return whether this Laurent polynomial is constant. - - EXAMPLES:: - - sage: L.<a, b> = LaurentPolynomialRing(QQ) - sage: L(0).is_constant() - True - sage: L(42).is_constant() - True - sage: a.is_constant() - False - sage: (1/b).is_constant() - False - """ - return (self._mon == ETuple({}, int(self._parent.ngens())) and - self._poly.is_constant()) - - def _symbolic_(self, R): - """ - EXAMPLES:: - - sage: R.<x,y> = LaurentPolynomialRing(QQ) - sage: f = x^3 + y/x - sage: g = f._symbolic_(SR); g - (x^4 + y)/x - sage: g(x=2,y=2) - 9 - - sage: g = SR(f) - sage: g(x=2,y=2) - 9 - """ - d = {repr(g): R.var(g) for g in self._parent.gens()} - return self.subs(**d) - - def derivative(self, *args): - r""" - The formal derivative of this Laurent polynomial, with respect - to variables supplied in args. - - Multiple variables and iteration counts may be supplied; see - documentation for the global :func:`derivative` function for more - details. - - .. SEEALSO:: - - :meth:`_derivative` - - EXAMPLES:: - - sage: R = LaurentPolynomialRing(ZZ,'x, y') - sage: x, y = R.gens() - sage: t = x**4*y+x*y+y+x**(-1)+y**(-3) - sage: t.derivative(x, x) - 12*x^2*y + 2*x^-3 - sage: t.derivative(y, 2) - 12*y^-5 - """ - return multi_derivative(self, args) - - # add .diff(), .differentiate() as aliases for .derivative() - diff = differentiate = derivative - - def _derivative(self, var=None): - """ - Computes formal derivative of this Laurent polynomial with - respect to the given variable. - - If var is among the generators of this ring, the derivative - is with respect to the generator. Otherwise, ``_derivative(var)`` is called - recursively for each coefficient of this polynomial. - - .. SEEALSO:: :meth:`derivative` - - EXAMPLES:: - - sage: R = LaurentPolynomialRing(ZZ,'x, y') - sage: x, y = R.gens() - sage: t = x**4*y+x*y+y+x**(-1)+y**(-3) - sage: t._derivative(x) - 4*x^3*y + y - x^-2 - sage: t._derivative(y) - x^4 + x + 1 - 3*y^-4 - - sage: R = LaurentPolynomialRing(QQ['z'],'x') - sage: z = R.base_ring().gen() - sage: x = R.gen() - sage: t = 33*z*x**4+x**(-1) - sage: t._derivative(z) - 33*x^4 - sage: t._derivative(x) - -x^-2 + 132*z*x^3 - """ - if var is None: - raise ValueError("must specify which variable to differentiate " - "with respect to") - P = self._parent - cdef list gens = list(P.gens()) - - # check if var is one of the generators - try: - index = gens.index(var) - except ValueError: - # call _derivative() recursively on coefficients - return P({m: c._derivative(var) - for (m, c) in self.dict().iteritems()}) - - # compute formal derivative with respect to generator - cdef dict d = {} - for m, c in self.dict().iteritems(): - if m[index] != 0: - new_m = [u for u in m] - new_m[index] += -1 - d[ETuple(new_m)] = m[index] * c - return P(d) - - def is_univariate(self): - """ - Return ``True`` if this is a univariate or constant Laurent polynomial, - and ``False`` otherwise. - - EXAMPLES:: - - sage: R.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = (x^3 + y^-3)*z - sage: f.is_univariate() - False - sage: g = f(1,y,4) - sage: g.is_univariate() - True - sage: R(1).is_univariate() - True - """ - return len(self.variables()) < 2 - - def univariate_polynomial(self, R=None): - """ - Returns a univariate polynomial associated to this - multivariate polynomial. - - INPUT: - - - ``R`` - (default: ``None``) a univariate Laurent polynomial ring - - If this polynomial is not in at most one variable, then a - ``ValueError`` exception is raised. The new polynomial is over - the same base ring as the given ``LaurentPolynomial`` and in the - variable ``x`` if no ring ``R`` is provided. - - EXAMPLES:: - - sage: R.<x, y> = LaurentPolynomialRing(ZZ) - sage: f = 3*x^2 - 2*y^-1 + 7*x^2*y^2 + 5 - sage: f.univariate_polynomial() - Traceback (most recent call last): - ... - TypeError: polynomial must involve at most one variable - sage: g = f(10,y); g - 700*y^2 + 305 - 2*y^-1 - sage: h = g.univariate_polynomial(); h - -2*y^-1 + 305 + 700*y^2 - sage: h.parent() - Univariate Laurent Polynomial Ring in y over Integer Ring - sage: g.univariate_polynomial(LaurentPolynomialRing(QQ,'z')) - -2*z^-1 + 305 + 700*z^2 - - Here's an example with a constant multivariate polynomial:: - - sage: g = R(1) - sage: h = g.univariate_polynomial(); h - 1 - sage: h.parent() - Univariate Laurent Polynomial Ring in x over Integer Ring - """ - from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing - v = self.variables() - if len(v) > 1: - raise TypeError("polynomial must involve at most one variable") - elif len(v) == 1: - x = v[0] - i = self._parent.gens().index(x) - x = str(x) - else: - x = 'x' - i = 0 - - #construct ring if none - if R is None: - R = LaurentPolynomialRing(self.base_ring(), x) - - return R({m[i]: c for m,c in self.dict().iteritems()}) - - def factor(self): - """ - Returns a Laurent monomial (the unit part of the factorization) and a factored multi-polynomial. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 - sage: f.factor() - (x^3*y^-7*z^-2) * (4*x^4*y^7*z + 3*y^8*z^2 + 2*x*y^7 + x^3*z^2) - - TESTS: - - Tests for :trac:`29173`:: - - sage: L.<a, b> = LaurentPolynomialRing(ZZ, 'a, b') - sage: (a*b + a + b + 1).factor() - (b + 1) * (a + 1) - sage: ((a^-1)*(a*b + a + b + 1)).factor() - (a^-1) * (b + 1) * (a + 1) - sage: L(-12).factor() - -1 * 2^2 * 3 - """ - pf = self._poly.factor() - - if self._poly.degree() == 0: - # Factorization is broken for polynomials, see - # https://github.com/sagemath/sage/issues/20214 - return pf - - u = self.parent(pf.unit()) - - cdef tuple g = <tuple> self._parent.gens() - for i in self._mon.nonzero_positions(): - u *= g[i] ** self._mon[i] - - cdef list f = [] - cdef dict d - for t in pf: - d = <dict> (t[0].dict()) - if len(d) == 1: # monomials are units - u *= self.parent(d) ** t[1] - else: - f.append((self.parent(d), t[1])) - - return Factorization(f, unit=u) - - def is_square(self, root=False): - r""" - Test whether this Laurent polynomial is a square. - - INPUT: - - - ``root`` - boolean (default ``False``) - if set to ``True`` - then return a pair ``(True, sqrt)`` with ``sqrt`` a square - root of this Laurent polynomial when it exists or - ``(False, None)``. - - EXAMPLES:: - - sage: L.<x,y,z> = LaurentPolynomialRing(QQ) - sage: p = (1 + x*y + z^-3) - sage: (p**2).is_square() - True - sage: (p**2).is_square(root=True) - (True, x*y + 1 + z^-3) - - sage: x.is_square() - False - sage: x.is_square(root=True) - (False, None) - - sage: (x**-4 * (1 + z)).is_square(root=False) - False - sage: (x**-4 * (1 + z)).is_square(root=True) - (False, None) - """ - self._normalize() - if not self._mon.is_multiple_of(2): - return (False, None) if root else False - - cdef LaurentPolynomial_mpair ans - - if not root: - return self._poly.is_square(root=False) - else: - (pans, root) = self._poly.is_square(root=True) - if not pans: - return (False, None) - - mon = self._mon.escalar_div(2) - ans = self._new_c() - ans._mon = mon - ans._poly = root - return (True, ans) - - cpdef rescale_vars(self, dict d, h=None, new_ring=None): - r""" - Rescale variables in a Laurent polynomial. - - INPUT: - - - ``d`` -- a ``dict`` whose keys are the generator indices - and values are the coefficients; so a pair ``(i, v)`` - means `x_i \mapsto v x_i` - - ``h`` -- (optional) a map to be applied to coefficients - done after rescaling - - ``new_ring`` -- (optional) a new ring to map the result into - - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) - sage: p = x^-2*y + x*y^-2 - sage: p.rescale_vars({0: 2, 1: 3}) - 2/9*x*y^-2 + 3/4*x^-2*y - sage: F = GF(2) - sage: p.rescale_vars({0: 3, 1: 7}, new_ring=L.change_ring(F)) - x*y^-2 + x^-2*y - - Test for :trac:`30331`:: - - sage: F.<z> = CyclotomicField(3) - sage: p.rescale_vars({0: 2, 1: z}, new_ring=L.change_ring(F)) - 2*z*x*y^-2 + 1/4*z*x^-2*y - """ - cdef int i - cdef dict df - cdef ETuple v - cdef LaurentPolynomial_mpair ans - - if self._prod is None: - self._compute_polydict() - - df = dict(self._prod.__repn) # This makes a copy for us to manipulate - if new_ring is None: - R = self._parent._base - else: - R = new_ring._base - if h is None: - for v in df: - val = df[v] - for i in d: - val *= d[i]**v[i] - df[v] = val - else: - for v in df: - val = df[v] - for i in d: - val *= d[i]**v[i] - df[v] = R(h(val)) - - ans = <LaurentPolynomial_mpair> self._new_c() - ans._prod = PolyDict(df) - ans._mon = self._mon - if new_ring is None: - S = self._poly._parent - else: - S = self._poly._parent.change_ring(R) - ans._poly = <MPolynomial> S({v.esub(ans._mon): df[v] for v in df}) - if new_ring is not None: - return new_ring(ans) - return ans - - cpdef toric_coordinate_change(self, M, h=None, new_ring=None): - r""" - Apply a matrix to the exponents in a Laurent polynomial. - - For efficiency, we implement this directly, rather than as a substitution. - - The optional argument ``h`` is a map to be applied to coefficients. - - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) - sage: p = 2*x^2 + y - x*y - sage: p.toric_coordinate_change(Matrix([[1,-3],[1,1]])) - 2*x^2*y^2 - x^-2*y^2 + x^-3*y - sage: F = GF(2) - sage: p.toric_coordinate_change(Matrix([[1,-3],[1,1]]), new_ring=L.change_ring(F)) - x^-2*y^2 + x^-3*y - - """ - cdef int n, i, j, x - cdef dict d, dr - cdef ETuple v - cdef LaurentPolynomial_mpair ans - cdef list L, mon, exp - cdef Matrix mat = M - - n = self._parent.ngens() - if mat.dimensions() != (n, n): - raise ValueError("the matrix M must be a {k} x {k} matrix".format(k=n)) - - if not self: - if new_ring is None: - return self._parent.zero() - else: - return new_ring.zero() - - if self._prod is None: - self._compute_polydict() - - d = self._prod.__repn - dr = {} - mon = [0] * n - for v in d: - # Make a copy of mon as this might be faster than creating the data from scratch. - # We will set every entry, so no need to clear the data. - exp = list(mon) - for j in range(n): - x = 0 - for i in range(n): - if not mat.get_is_zero_unsafe(j, i): - x += (<int> v[i]) * int(mat.get_unsafe(j, i)) - if x < (<int> mon[j]): - mon[j] = x - exp[j] = x - dr[ETuple(exp)] = d[v] - - if h is not None: - for v in dr: - dr[v] = self._parent._base(h(dr[v])) - - ans = <LaurentPolynomial_mpair> self._new_c() - ans._prod = PolyDict(dr) - ans._mon = ETuple(mon) - ans._poly = <MPolynomial> self._poly._parent({v.esub(ans._mon): dr[v] for v in dr}) - if new_ring is not None: - return new_ring(ans) - return ans - - cpdef toric_substitute(self, v, v1, a, h=None, new_ring=None): - r""" - Perform a single-variable substitution up to a toric coordinate change. - - The optional argument ``h`` is a map to be applied to coefficients. - - EXAMPLES:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) - sage: p = x + y - sage: p.toric_substitute((2,3), (-1,1), 2) - 1/2*x^3*y^3 + 2*x^-2*y^-2 - sage: F = GF(5) - sage: p.toric_substitute((2,3), (-1,1), 2, new_ring=L.change_ring(F)) - 3*x^3*y^3 + 2*x^-2*y^-2 - - TESTS: - - Tests for :trac:`30331`:: - - sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) - sage: p = x + y - sage: F.<z> = CyclotomicField(3) - sage: p.toric_substitute((2,3), (-1,1), z, new_ring=L.change_ring(F)) - (-z - 1)*x^3*y^3 + z*x^-2*y^-2 - - sage: P.<x> = LaurentPolynomialRing(QQ, 1) - sage: u = x - 1 - sage: v = u.toric_substitute((-1,), (-1,), 1) - sage: v.is_zero() - True - """ - cdef dict d, dr - cdef ETuple ve, v1e, w, w1, mon - cdef LaurentPolynomial_mpair ans - cdef int t - - if self._prod is None: - self._compute_polydict() - - d = self._prod.__repn - dr = {} - ve = ETuple(v) - v1e = ETuple(v1) - mon = self._mon - if h is not None: - d = dict(d) # Make a copy so we can manipulate it - for w in d: - d[w] = h(d[w]) - for w in d: - x = d[w] - t = w.dotprod(v1e) - w1 = w.eadd_scaled(ve, -t) - if w1 in dr: - dr[w1] += x * a**t - else: - dr[w1] = x * a**t - mon = mon.emin(w1) - for v in tuple(dr.keys()): - if not dr[v]: - del dr[v] - - if new_ring is None: - S = self._poly._parent - else: - S = self._poly._parent.change_ring(new_ring._base) - ans = <LaurentPolynomial_mpair> self._new_c() - ans._prod = PolyDict(dr) - ans._mon = mon - ans._poly = <MPolynomial> S({v.esub(ans._mon): dr[v] for v in dr}) - if new_ring is not None: - return new_ring(ans) - return ans diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index aaa1166b9d2..f56b911ad3b 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -42,10 +42,11 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.element import parent -from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial_mpair, LaurentPolynomial_univariate +from sage.misc.lazy_import import LazyImport +from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial_univariate from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.structure.element import parent def is_LaurentPolynomialRing(R): @@ -586,7 +587,7 @@ def __init__(self, R): raise ValueError("base ring must be an integral domain") LaurentPolynomialRing_generic.__init__(self, R) - Element = LaurentPolynomial_mpair + Element = LazyImport('sage.rings.polynomial.laurent_polynomial_mpair', 'LaurentPolynomial_mpair') def _repr_(self): """ From 21b23bfd96d646de42ed37d057a4f7df2dc5fd95 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe <mkoeppe@math.ucdavis.edu> Date: Wed, 19 Apr 2023 18:54:40 -0700 Subject: [PATCH 2/8] sage.rings.polynomial.laurent_polynomial_mpair: Split out from laurent_polynomial --- .../polynomial/laurent_polynomial_mpair.pxd | 13 + .../polynomial/laurent_polynomial_mpair.pyx | 1828 +++++++++++++++++ 2 files changed, 1841 insertions(+) create mode 100644 src/sage/rings/polynomial/laurent_polynomial_mpair.pxd create mode 100644 src/sage/rings/polynomial/laurent_polynomial_mpair.pyx diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pxd b/src/sage/rings/polynomial/laurent_polynomial_mpair.pxd new file mode 100644 index 00000000000..eb31593dc77 --- /dev/null +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pxd @@ -0,0 +1,13 @@ +from sage.rings.polynomial.multi_polynomial cimport MPolynomial +from sage.rings.polynomial.polydict cimport ETuple, PolyDict + + +cdef class LaurentPolynomial_mpair(LaurentPolynomial): + cdef ETuple _mon + cdef MPolynomial _poly + cdef PolyDict _prod + cdef _compute_polydict(self) + cdef _normalize(self, i=*) + cpdef rescale_vars(self, dict d, h=*, new_ring=*) + cpdef toric_coordinate_change(self, M, h=*, new_ring=*) + cpdef toric_substitute(self, v, v1, a, h=*, new_ring=*) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx new file mode 100644 index 00000000000..ceb64874f77 --- /dev/null +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -0,0 +1,1828 @@ +r""" +Elements of multivariate Laurent polynomial rings +""" + +# **************************************************************************** +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.rings.integer cimport Integer +from sage.categories.map cimport Map +from sage.structure.element import is_Element, coerce_binop, parent +from sage.structure.factorization import Factorization +from sage.misc.derivative import multi_derivative +from sage.rings.polynomial.polydict cimport monomial_exponent +from sage.rings.polynomial.polynomial_element import Polynomial +from sage.structure.richcmp cimport richcmp, rich_to_bool +from sage.matrix.matrix0 cimport Matrix + + +cdef class LaurentPolynomial_mpair(LaurentPolynomial): + """ + Multivariate Laurent polynomials. + """ + def __init__(self, parent, x, mon=None, reduce=True): + """ + Currently, one can only create LaurentPolynomials out of dictionaries + and elements of the base ring. + + INPUT: + + - ``parent`` -- a SageMath parent + + - ``x`` -- an element or dictionary or anything the underlying + polynomial ring accepts + + - ``mon`` -- (default: ``None``) a tuple specifying the shift + in the exponents + + - ``reduce`` -- (default: ``True``) a boolean + + EXAMPLES:: + + sage: L.<w,z> = LaurentPolynomialRing(QQ) + sage: f = L({(-1,-1):1}); f + w^-1*z^-1 + sage: f = L({(1,1):1}); f + w*z + sage: f = L({(-1,-1):1, (1,3):4}); f + 4*w*z^3 + w^-1*z^-1 + sage: L(1/2) + 1/2 + + TESTS: + + Check that :trac:`19538` is fixed:: + + sage: R = LaurentPolynomialRing(QQ,'x2,x0') + sage: S = LaurentPolynomialRing(QQ,'x',3) + sage: f = S.coerce_map_from(R) + sage: f(R.gen(0) + R.gen(1)^2) + x0^2 + x2 + sage: _.parent() + Multivariate Laurent Polynomial Ring in x0, x1, x2 over Rational Field + + :: + + sage: from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial_mpair + sage: LaurentPolynomial_mpair(L, {(1,2): 1/42}, mon=(-3, -3)) + 1/42*w^-2*z^-1 + + :trac:`22398`:: + + sage: LQ = LaurentPolynomialRing(QQ, 'x0, x1, x2, y0, y1, y2, y3, y4, y5') + sage: LZ = LaurentPolynomialRing(ZZ, 'x0, x1, x2, y0, y1, y2, y3, y4, y5') + sage: LQ.inject_variables() + Defining x0, x1, x2, y0, y1, y2, y3, y4, y5 + sage: x2^-1*y0*y1*y2*y3*y4*y5 + x1^-1*x2^-1*y0*y1*y3*y4 + x0^-1 in LZ + True + sage: x2^-1*y0*y1*y2*y3*y4*y5 + x1^-1*x2^-1*y0*y1*y3*y4 + x0^-1*x1^-1*y0*y3 + x0^-1 in LZ + True + + Check that input is not modified:: + + sage: LQ.<x,y> = LaurentPolynomialRing(QQ) + sage: D = {(-1, 1): 1} + sage: k = tuple(D)[0] + sage: v = D[k] + sage: type(k), type(v) + (<... 'tuple'>, <class 'sage.rings.integer.Integer'>) + sage: LQ(D) + x^-1*y + sage: tuple(D)[0] is k + True + sage: D[k] is v + True + """ + if isinstance(x, PolyDict): + x = x.dict() + if mon is not None: + if isinstance(mon, ETuple): + self._mon = mon + else: + self._mon = ETuple(mon) + else: + if isinstance(x, dict): + self._mon = ETuple({}, int(parent.ngens())) + D = {} + for k, x_k in x.iteritems(): # ETuple-ize keys, set _mon + if not isinstance(k, (tuple, ETuple)) or len(k) != parent.ngens(): + self._mon = ETuple({}, int(parent.ngens())) + break + if isinstance(k, tuple): + k = ETuple(k) + D[k] = x_k + self._mon = self._mon.emin(k) # point-wise min of _mon and k + else: + x = D + if not self._mon.is_constant(): # factor out _mon + x = {k.esub(self._mon): x_k for k, x_k in x.iteritems()} + elif (isinstance(x, LaurentPolynomial_mpair) and + parent.variable_names() == x.parent().variable_names()): + self._mon = (<LaurentPolynomial_mpair>x)._mon + x = (<LaurentPolynomial_mpair>x)._poly + else: # since x should coerce into parent, _mon should be (0,...,0) + self._mon = ETuple({}, int(parent.ngens())) + self._poly = parent._R(x) + CommutativeAlgebraElement.__init__(self, parent) + + def __reduce__(self): + """ + TESTS:: + + sage: R = LaurentPolynomialRing(QQ, 2, 'x') + sage: R.<x1,x2> = LaurentPolynomialRing(QQ) + sage: loads(dumps(x1)) == x1 # indirect doctest + True + sage: z = x1/x2 + sage: loads(dumps(z)) == z + True + """ + return self._parent, (self._poly, self._mon) + + def __hash__(self): + r""" + TESTS: + + Test that the hash is non-constant (see also :trac:`27914`):: + + sage: L.<w,z> = LaurentPolynomialRing(QQ) + sage: len({hash(w^i*z^j) for i in [-2..2] for j in [-2..2]}) + 25 + + Check that :trac:`20490` is fixed:: + + sage: R.<a,b> = LaurentPolynomialRing(ZZ) + sage: p = a*~a + sage: p._fraction_pair() + (a, a) + sage: p == R.one() + True + sage: hash(p) + 1 + + Check that :trac:`23864` is fixed (compatibility with integers, rationals + and polynomial rings):: + + sage: L = LaurentPolynomialRing(QQ, 'x0,x1,x2') + sage: hash(L.zero()) + 0 + sage: hash(L.one()) + 1 + sage: hash(-L.one()) + -2 + sage: hash(L(1/2)) == hash(1/2) + True + + sage: R = PolynomialRing(QQ, 'x0,x1,x2') + sage: x0,x1,x2 = R.gens() + sage: hash(x0) == hash(L(x0)) + True + sage: hash(1 - 7*x0 + x1*x2) == hash(L(1 - 7*x0 + x1*x2)) + True + + Check that :trac:`27914` is fixed:: + + sage: L.<w,z> = LaurentPolynomialRing(QQ) + sage: Lw = LaurentPolynomialRing(QQ, 'w') + sage: Lz = LaurentPolynomialRing(QQ, 'z') + sage: all(hash(w^k) == hash(Lw(w^k)) + ....: and hash(z^k) == hash(Lz(z^k)) for k in (-5..5)) + True + sage: p = w^-1 + 2 + w + sage: hash(p) == hash(Lw(p)) + True + """ + # we reimplement the hash from multipolynomial to handle negative exponents + # (see multi_polynomial.pyx) + cdef long result = 0 + cdef long exponent + cdef list var_name_hash = [hash(v) for v in self._parent.variable_names()] + cdef int p + cdef int n = len(var_name_hash) + cdef long c_hash + for m, c in self._poly.iterator_exp_coeff(): + c_hash = hash(c) + if c_hash != 0: + for p in range(n): + exponent = m[p] + self._mon[p] + if exponent > 0: + c_hash = (1000003 * c_hash) ^ var_name_hash[p] + c_hash = (1000003 * c_hash) ^ exponent + elif exponent < 0: + c_hash = (1000003 * c_hash) ^ var_name_hash[p] + c_hash = (700005 * c_hash) ^ exponent + result += c_hash + + return result + + def _im_gens_(self, codomain, im_gens, base_map=None): + """ + Return the image of ``self`` under the morphism defined by + ``im_gens`` in ``codomain``. + + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(ZZ) + sage: M.<u,v> = LaurentPolynomialRing(ZZ) + sage: phi = L.hom([u,v]) + sage: phi(x^2*~y -5*y**3) # indirect doctest + -5*v^3 + u^2*v^-1 + + TESTS: + + check compatibility with :trac:`26105`:: + + sage: F.<t> = GF(4) # optional - sage.rings.finite_rings + sage: LF.<a,b> = LaurentPolynomialRing(F) # optional - sage.rings.finite_rings + sage: rho = LF.hom([b,a], base_map=F.frobenius_endomorphism()) # optional - sage.rings.finite_rings + sage: s = t*~a + b +~t*(b**-3)*a**2; rs = rho(s); rs # optional - sage.rings.finite_rings + a + (t + 1)*b^-1 + t*a^-3*b^2 + sage: s == rho(rs) # optional - sage.rings.finite_rings + True + """ + p = self._poly + m = self._mon + if base_map is not None: + p = p.map_coefficients(base_map) + from sage.misc.misc_c import prod + return codomain(p(im_gens) * prod(ig**m[im_gens.index(ig)] for ig in im_gens)) + + cdef _normalize(self, i=None): + r""" + Remove the common monomials from ``self._poly`` and store + them in ``self._mon``. + + INPUT: + + - ``i`` -- an integer + + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ) + sage: f = x*y + 2*y*x^2 + y # indirect doctest + sage: f.factor() # Notice the y has been factored out. + (y) * (2*x^2 + x + 1) + + Check that :trac:`23864` has been fixed:: + + sage: hash(L.zero()) + 0 + """ + if not self._poly: + self._mon = ETuple({}, int(self._parent.ngens())) + return + + #cdef dict D = <dict> self._poly._mpoly_dict_recursive( + # <tuple> self._parent.variable_names(), + # self._parent.base_ring() + # ) + cdef dict D = <dict> self._poly.dict() + + cdef ETuple e + if i is None: + e = None + for k in D: + if e is None: + e = <ETuple> k + else: + e = e.emin(k) + if not e.is_constant(): + self._poly = <ModuleElement> (self._poly // self._poly._parent({e: 1})) + self._mon = self._mon.eadd(e) + else: + e = None + for k in D: + if e is None or k[i] < e: + e = <ETuple> k[i] + if e > 0: + self._poly = <ModuleElement> (self._poly // self._poly._parent.gen(i)) + self._mon = self._mon.eadd_p(e, i) + + cdef _compute_polydict(self): + """ + EXAMPLES:: + + sage: L.<w,z> = LaurentPolynomialRing(QQ) + sage: a = w^2*z^-1 +3 + sage: a.dict() # indirect doctest + {(0, 0): 3, (2, -1): 1} + """ + #cdef dict D = <dict> self._poly._mpoly_dict_recursive(self._parent.variable_names(), + # self._parent.base_ring()) + cdef dict D = <dict> self._poly.dict() + cdef dict DD + if self._mon.is_constant(): + self._prod = PolyDict(D) + return + DD = {} + for k in D: + DD[k.eadd(self._mon)] = D[k] + self._prod = PolyDict(DD) + + def is_unit(self): + """ + Return ``True`` if ``self`` is a unit. + + The ground ring is assumed to be an integral domain. + + This means that the Laurent polynomial is a monomial + with unit coefficient. + + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ) + sage: (x*y/2).is_unit() + True + sage: (x + y).is_unit() + False + sage: (L.zero()).is_unit() + False + sage: (L.one()).is_unit() + True + + sage: L.<x,y> = LaurentPolynomialRing(ZZ) + sage: (2*x*y).is_unit() + False + """ + coeffs = self.coefficients() + if len(coeffs) != 1: + return False + return coeffs[0].is_unit() + + def _repr_(self): + """ + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ) + sage: f = x^2 + x*y/2 + 2*y^-1 + sage: f._repr_() + 'x^2 + 1/2*x*y + 2*y^-1' + """ + if self._prod is None: + self._compute_polydict() + try: + key = self.parent().term_order().sortkey + except AttributeError: + key = None + atomic = self.parent().base_ring()._repr_option('element_is_atomic') + return self._prod.poly_repr(self.parent().variable_names(), + atomic_coefficients=atomic, sortkey=key) + + def _latex_(self): + r""" + EXAMPLES:: + + sage: L.<w,z> = LaurentPolynomialRing(QQ) + sage: a = w^2*z^-1+3; a + w^2*z^-1 + 3 + sage: latex(a) + w^{2} z^{-1} + 3 + + TESTS:: + + sage: L.<lambda2, y2> = LaurentPolynomialRing(QQ) + sage: latex(1/lambda2 + y2^(-3)) + \lambda_{2}^{-1} + y_{2}^{-3} + """ + if self._prod is None: + self._compute_polydict() + try: + key = self.parent().term_order().sortkey + except AttributeError: + key = None + atomic = self.parent().base_ring()._repr_option('element_is_atomic') + return self._prod.latex(self.parent().latex_variable_names(), + atomic_coefficients=atomic, sortkey=key) + + cpdef long number_of_terms(self) except -1: + """ + Return the number of non-zero coefficients of ``self``. + + Also called weight, hamming weight or sparsity. + + EXAMPLES:: + + sage: R.<x, y> = LaurentPolynomialRing(ZZ) + sage: f = x^3 - y + sage: f.number_of_terms() + 2 + sage: R(0).number_of_terms() + 0 + sage: f = (x+1/y)^100 + sage: f.number_of_terms() + 101 + + The method :meth:`hamming_weight` is an alias:: + + sage: f.hamming_weight() + 101 + """ + return self._poly.number_of_terms() + + def __invert__(LaurentPolynomial_mpair self): + """ + Return the inverse of ``self``. + + This treats monomials specially so they remain Laurent + polynomials; the inverse of any other polynomial is an element + of the rational function field. + + TESTS:: + + sage: L.<x,y> = LaurentPolynomialRing(ZZ) + sage: f = ~x + sage: parent(f) + Multivariate Laurent Polynomial Ring in x, y over Integer Ring + sage: parent(f.coefficients()[0]) is parent(f).base_ring() + True + sage: g = ~(2*x) + sage: parent(g) + Multivariate Laurent Polynomial Ring in x, y over Rational Field + sage: parent(g.coefficients()[0]) is parent(g).base_ring() + True + """ + cdef ETuple e + if self._poly.is_term(): + (e, c), = self.dict().items() + e = e.emul(-1) + P = self._parent + try: + c = c.inverse_of_unit() + except (AttributeError, ZeroDivisionError, ArithmeticError): + c = ~c + if c.parent() is not P.base_ring(): + P = P.change_ring(c.parent()) + return P({e: c}) + return super().__invert__() + + def __pow__(LaurentPolynomial_mpair self, n, m): + """ + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ) + sage: f = x + y + sage: f^2 + x^2 + 2*x*y + y^2 + sage: f^(-1) + 1/(x + y) + + TESTS: + + Check that :trac:`2952` is fixed:: + + sage: R.<q> = QQ[] + sage: L.<x,y,z> = LaurentPolynomialRing(R) + sage: f = (x+y+z^-1)^2 + sage: f.substitute(z=1) + x^2 + 2*x*y + y^2 + 2*x + 2*y + 1 + """ + cdef LaurentPolynomial_mpair ans + if n < 0: + return ~(self ** -n) + ans = self._new_c() + ans._poly = self._poly ** n + ans._mon = self._mon.emul(n) + return ans + + def __getitem__(self, n): + r""" + Return the coefficient of `x^n = x_1^{n_1} \cdots x_k^{n_k}` where + `n` is a tuple of length `k` and `k` is the number of variables. + + If the number of inputs is not equal to the number of variables, this + raises a ``TypeError``. + + EXAMPLES:: + + sage: P.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 + x*z; f + -x^6 + x*z - 7*x^-2*y^3 + 5*x^-2*y + x^-3*y^2 + sage: f[6,0,0] + -1 + sage: f[-2,3,0] + -7 + sage: f[-1,4,2] + 0 + sage: f[1,0,1] + 1 + sage: f[6] + Traceback (most recent call last): + ... + TypeError: must have exactly 3 inputs + sage: f[6,0] + Traceback (most recent call last): + ... + TypeError: must have exactly 3 inputs + sage: f[6,0,0,0] + Traceback (most recent call last): + ... + TypeError: must have exactly 3 inputs + """ + if isinstance(n, slice): + raise TypeError("multivariate Laurent polynomials are not iterable") + if not isinstance(n, tuple) or len(n) != self._parent.ngens(): + raise TypeError("must have exactly %s inputs" % + self.parent().ngens()) + cdef ETuple t = ETuple(n) + if self._prod is None: + self._compute_polydict() + try: + return self._prod[t] + except KeyError: + return self._parent.base_ring().zero() + + def __iter__(self): + """ + Iterate through all terms by returning a list of the coefficient and + the corresponding monomial. + + EXAMPLES:: + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 + sage: sorted(f) # indirect doctest + [(-7, x^-2*y^3), (-1, x^6), (1, x^-3*y^2), (5, x^-2*y)] + """ + P = self._parent + one = P._R.one() + if self._mon.is_constant(): + for exp, coeff in self._poly.iterator_exp_coeff(): + yield (coeff, P.element_class(P, one, exp)) + else: + for exp, coeff in self._poly.iterator_exp_coeff(): + yield (coeff, P.element_class(P, one, exp.eadd(self._mon))) + + def iterator_exp_coeff(self): + """ + Iterate over ``self`` as pairs of (ETuple, coefficient). + + EXAMPLES:: + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 + sage: list(f.iterator_exp_coeff()) + [((6, 0), -1), ((-2, 3), -7), ((-2, 1), 5), ((-3, 2), 1)] + """ + for exp, coeff in self._poly.iterator_exp_coeff(): + yield (exp.eadd(self._mon), coeff) + + def monomials(self): + """ + Return the list of monomials in ``self``. + + EXAMPLES:: + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 + sage: sorted(f.monomials()) + [x^-3*y^2, x^-2*y, x^-2*y^3, x^6] + """ + return [mon for coeff, mon in self] + + def monomial_coefficient(self, mon): + """ + Return the coefficient in the base ring of the monomial ``mon`` in + ``self``, where ``mon`` must have the same parent as ``self``. + + This function contrasts with the function :meth:`coefficient()` + which returns the coefficient of a monomial viewing this + polynomial in a polynomial ring over a base ring having fewer + variables. + + INPUT: + + - ``mon`` -- a monomial + + .. SEEALSO:: + + For coefficients in a base ring of fewer variables, see + :meth:`coefficient()`. + + EXAMPLES:: + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^3 + 5*x*y)*x^-3 + sage: f.monomial_coefficient(x^-2*y^3) + -7 + sage: f.monomial_coefficient(x^2) + 0 + + TESTS:: + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + sage: f = y^2 * x^-2 + sage: f.monomial_coefficient(x + y) + Traceback (most recent call last): + ... + ValueError: not a monomial + """ + if parent(mon) != self._parent: + raise TypeError("input must have the same parent") + cdef LaurentPolynomial_mpair m = <LaurentPolynomial_mpair> mon + if m._prod is None: + m._compute_polydict() + if self._prod is None: + self._compute_polydict() + exp = monomial_exponent(m._prod) + zero = self._parent.base_ring().zero() + return self._prod.get(exp, zero) + + def constant_coefficient(self): + """ + Return the constant coefficient of ``self``. + + EXAMPLES:: + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^2 + 5*x*y)*x^-3; f + -x^6 - 7*x^-2*y^2 + 5*x^-2*y + x^-3*y^2 + sage: f.constant_coefficient() + 0 + sage: f = (x^3 + 2*x^-2*y+y^3)*y^-3; f + x^3*y^-3 + 1 + 2*x^-2*y^-2 + sage: f.constant_coefficient() + 1 + """ + return self[(0,)*self._parent.ngens()] + + def coefficient(self, mon): + r""" + Return the coefficient of ``mon`` in ``self``, where ``mon`` must + have the same parent as ``self``. + + The coefficient is defined as follows. If `f` is this polynomial, then + the coefficient `c_m` is sum: + + .. MATH:: + + c_m := \sum_T \frac{T}{m} + + where the sum is over terms `T` in `f` that are exactly divisible + by `m`. + + A monomial `m(x,y)` 'exactly divides' `f(x,y)` if `m(x,y) | f(x,y)` + and neither `x \cdot m(x,y)` nor `y \cdot m(x,y)` divides `f(x,y)`. + + INPUT: + + - ``mon`` -- a monomial + + OUTPUT: + + Element of the parent of ``self``. + + .. NOTE:: + + To get the constant coefficient, call + :meth:`constant_coefficient()`. + + EXAMPLES:: + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + + The coefficient returned is an element of the parent of ``self``; in + this case, ``P``. :: + + sage: f = 2 * x * y + sage: c = f.coefficient(x*y); c + 2 + sage: c.parent() + Multivariate Laurent Polynomial Ring in x, y over Rational Field + + sage: P.<x,y> = LaurentPolynomialRing(QQ) + sage: f = (y^2 - x^9 - 7*x*y^2 + 5*x*y)*x^-3; f + -x^6 - 7*x^-2*y^2 + 5*x^-2*y + x^-3*y^2 + sage: f.coefficient(y) + 5*x^-2 + sage: f.coefficient(y^2) + -7*x^-2 + x^-3 + sage: f.coefficient(x*y) + 0 + sage: f.coefficient(x^-2) + -7*y^2 + 5*y + sage: f.coefficient(x^-2*y^2) + -7 + sage: f.coefficient(1) + -x^6 - 7*x^-2*y^2 + 5*x^-2*y + x^-3*y^2 + """ + if mon.parent() is not self._parent: + mon = self._parent(mon) + cdef LaurentPolynomial_mpair m = <LaurentPolynomial_mpair> mon + if self._prod is None: + self._compute_polydict() + if m._prod is None: + m._compute_polydict() + return self._parent(self._prod.coefficient(m.dict())) + + def coefficients(self): + """ + Return the nonzero coefficients of ``self`` in a list. + + The returned list is decreasingly ordered by the term ordering + of ``self.parent()``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ, order='degrevlex') + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f.coefficients() + [4, 3, 2, 1] + sage: L.<x,y,z> = LaurentPolynomialRing(QQ,order='lex') + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f.coefficients() + [4, 1, 2, 3] + """ + return self._poly.coefficients() + + def variables(self, sort=True): + """ + Return a tuple of all variables occurring in ``self``. + + INPUT: + + - ``sort`` -- specifies whether the indices shall be sorted + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f.variables() + (z, y, x) + sage: f.variables(sort=False) #random + (y, z, x) + """ + cdef dict d = self.dict() + cdef tuple g = self._parent.gens() + cdef Py_ssize_t nvars = len(g) + cdef set vars = set() + for k in d: + vars.update(k.nonzero_positions()) + if len(vars) == nvars: + break + cdef list v = [g[i] for i in vars] + if sort: + v.sort() + return tuple(v) + + cpdef dict dict(self): + """ + Return ``self`` represented as a ``dict``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: sorted(f.dict().items()) + [((3, 1, 0), 3), ((4, 0, -2), 2), ((6, -7, 0), 1), ((7, 0, -1), 4)] + """ + if self._prod is None: + self._compute_polydict() + return <dict> self._prod.dict() + + def _fraction_pair(self): + """ + Return one representation of ``self`` as a pair + ``(numerator, denominator)``. + + Here both the numerator and the denominator are polynomials. + + This is used for coercion into the fraction field. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f._fraction_pair() + (4*x^7*y^7*z + 3*x^3*y^8*z^2 + 2*x^4*y^7 + x^6*z^2, y^7*z^2) + """ + ring = self._parent._R + numer = self._poly + denom = ring.one() + var = ring.gens() + for i, j in enumerate(self._mon): + if j > 0: + numer *= var[i] ** j + else: + denom *= var[i] ** (-j) + return (numer, denom) + + cpdef _add_(self, _right): + """ + Return the Laurent polynomial ``self + right``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + y^-1 + sage: g = y + z + sage: f + g + x + y + z + y^-1 + """ + cdef LaurentPolynomial_mpair ans = self._new_c() + cdef LaurentPolynomial_mpair right = <LaurentPolynomial_mpair>_right + ans._mon, a, b = self._mon.combine_to_positives(right._mon) + if not a.is_constant(): + ans._poly = self._poly * self._poly._parent({a: 1}) + else: + ans._poly = self._poly + if not b.is_constant(): + ans._poly += right._poly * self._poly._parent({b: 1}) + else: + ans._poly += right._poly + return ans + + cpdef _sub_(self, _right): + """ + Return the Laurent polynomial ``self - right``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + y^-1 + sage: g = y + z + x + sage: f - g + -y - z + y^-1 + """ + cdef LaurentPolynomial_mpair ans = self._new_c() + cdef LaurentPolynomial_mpair right = <LaurentPolynomial_mpair>_right + cdef ETuple a, b + ans._mon, a, b = self._mon.combine_to_positives(right._mon) + if not a.is_constant(): + ans._poly = self._poly * self._poly._parent({a: 1}) + else: + ans._poly = self._poly + if not b.is_constant(): + ans._poly -= right._poly * self._poly._parent({b: 1}) + else: + ans._poly -= right._poly + return ans + + cpdef _div_(self, rhs): + """ + Return the division of ``self`` by ``rhs``. + + If the denominator is not a unit, + the result will be given in the fraction field. + + EXAMPLES:: + + sage: R.<s,q,t> = LaurentPolynomialRing(QQ) + sage: 1/s + s^-1 + sage: 1/(s*q) + s^-1*q^-1 + sage: 1/(s+q) + 1/(s + q) + sage: (1/(s+q)).parent() + Fraction Field of Multivariate Polynomial Ring in s, q, t over Rational Field + sage: (1/(s*q)).parent() + Multivariate Laurent Polynomial Ring in s, q, t over Rational Field + sage: (s+q)/(q^2*t^(-2)) + s*q^-2*t^2 + q^-1*t^2 + """ + cdef LaurentPolynomial_mpair right = <LaurentPolynomial_mpair> rhs + if right.is_zero(): + raise ZeroDivisionError + if right._poly.is_term(): + return self * ~right + else: + return RingElement._div_(self, rhs) + + def is_monomial(self): + """ + Return ``True`` if ``self`` is a monomial. + + EXAMPLES:: + + sage: k.<y,z> = LaurentPolynomialRing(QQ) + sage: z.is_monomial() + True + sage: k(1).is_monomial() + True + sage: (z+1).is_monomial() + False + sage: (z^-2909).is_monomial() + True + sage: (38*z^-2909).is_monomial() + False + """ + return self._poly.is_monomial() + + cpdef _neg_(self): + """ + Return ``-self``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + y^-1 + sage: -f + -x - y^-1 + """ + cdef LaurentPolynomial_mpair ans = self._new_c() + ans._mon = self._mon + ans._poly = -self._poly + return ans + + cpdef _lmul_(self, Element right): + """ + Return ``self * right`` where ``right`` is in ``self``'s base ring. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + y^-1 + sage: f*(1/2) + 1/2*x + 1/2*y^-1 + """ + cdef LaurentPolynomial_mpair ans = self._new_c() + ans._mon = self._mon + ans._poly = self._poly * right + return ans + + cpdef _rmul_(self, Element left): + """ + Return ``left * self`` where ``left`` is in ``self``'s base ring. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + y^-1 + sage: (1/2)*f + 1/2*x + 1/2*y^-1 + """ + cdef LaurentPolynomial_mpair ans = self._new_c() + ans._mon = self._mon + ans._poly = left * self._poly + return ans + + cpdef _mul_(self, right): + """ + Return ``self * right``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + y^-1 + sage: g = y + z + sage: f*g + x*y + x*z + 1 + y^-1*z + """ + cdef LaurentPolynomial_mpair ans = self._new_c() + ans._mon = self._mon.eadd((<LaurentPolynomial_mpair>right)._mon) + ans._poly = self._poly * (<LaurentPolynomial_mpair>right)._poly + return ans + + cpdef _floordiv_(self, right): + """ + Perform division with remainder and return the quotient. + + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ) + sage: f = x^3 + y^-3 + sage: g = y + x + sage: f // g + x^5*y^-3 - x^4*y^-2 + x^3*y^-1 + + sage: h = x + y^(-1) + sage: f // h + x^2 - x*y^-1 + y^-2 + sage: h * (f // h) == f + True + sage: f // 1 + x^3 + y^-3 + sage: 1 // f + 0 + + TESTS: + + Check that :trac:`19357` is fixed:: + + sage: x // y + x*y^-1 + + Check that :trac:`21999` is fixed:: + + sage: L.<a,b> = LaurentPolynomialRing(QQbar) + sage: (a+a*b) // a + b + 1 + """ + cdef LaurentPolynomial_mpair ans = self._new_c() + cdef LaurentPolynomial_mpair rightl = <LaurentPolynomial_mpair> right + self._normalize() + rightl._normalize() + ans._mon = self._mon.esub(rightl._mon) + ans._poly = self._poly // rightl._poly + return ans + + @coerce_binop + def quo_rem(self, right): + """ + Divide this Laurent polynomial by ``right`` and return a quotient and + a remainder. + + INPUT: + + - ``right`` -- a Laurent polynomial + + OUTPUT: + + A pair of Laurent polynomials. + + EXAMPLES:: + + sage: R.<s, t> = LaurentPolynomialRing(QQ) + sage: (s^2 - t^2).quo_rem(s - t) + (s + t, 0) + sage: (s^-2 - t^2).quo_rem(s - t) + (s + t, -s^2 + s^-2) + sage: (s^-2 - t^2).quo_rem(s^-1 - t) + (t + s^-1, 0) + + TESTS: + + Verify that :trac:`31257` is fixed:: + + sage: R.<x,y> = LaurentPolynomialRing(QQ) + sage: q, r = (1/x).quo_rem(y) + sage: q, r + (x^-1*y^-1, 0) + sage: q*y + r == 1/x + True + sage: q,r = (x^-2 - y^2).quo_rem(x - y) + sage: q*(x - y) + r == x^-2 - y^2 + True + """ + # make copies of self and right so that the input can be normalized + # without affecting the objects that were passed to the method + cdef LaurentPolynomial_mpair selfl = self._new_c() + selfl._poly = self._poly + selfl._mon = self._mon + cdef LaurentPolynomial_mpair rightl = self._new_c() + rightl._poly = (<LaurentPolynomial_mpair> right)._poly + rightl._mon = (<LaurentPolynomial_mpair> right)._mon + + selfl._normalize() + rightl._normalize() + q, r = selfl._poly.quo_rem(rightl._poly) + ql = LaurentPolynomial_mpair(self._parent, q, + mon=selfl._mon.esub(rightl._mon)) + rl = LaurentPolynomial_mpair(self._parent, r, + mon=selfl._mon) + ql._normalize() + rl._normalize() + return (ql, rl) + + cpdef _richcmp_(self, right, int op): + """ + Compare two polynomials in a `LaurentPolynomialRing` based on the term + order from the parent ring. If the parent ring does not specify a term + order then only comparison by equality is supported. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + y^-1 + sage: g = y + z + sage: f == f + True + sage: f == g + False + sage: f == 2 + False + """ + if self._prod is None: + self._compute_polydict() + if (<LaurentPolynomial_mpair> right)._prod is None: + (<LaurentPolynomial_mpair> right)._compute_polydict() + + try: + sortkey = self._parent.term_order().sortkey + except AttributeError: + sortkey = None + + return self._prod.rich_compare((<LaurentPolynomial_mpair>right)._prod, + op, sortkey) + + def exponents(self): + """ + Return a list of the exponents of ``self``. + + EXAMPLES:: + + sage: L.<w,z> = LaurentPolynomialRing(QQ) + sage: a = w^2*z^-1 + 3; a + w^2*z^-1 + 3 + sage: e = a.exponents() + sage: e.sort(); e + [(0, 0), (2, -1)] + + """ + return [a.eadd(self._mon) for a in self._poly.exponents()] + + def degree(self, x=None): + """ + Return the degree of ``x`` in ``self``. + + EXAMPLES:: + + sage: R.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f.degree(x) + 7 + sage: f.degree(y) + 1 + sage: f.degree(z) + 0 + """ + if not x: + return self._poly.total_degree() + sum(self._mon) + + cdef tuple g = <tuple> self._parent.gens() + cdef Py_ssize_t i + cdef bint no_generator_found = True + for i in range(len(g)): + if g[i] is x: + no_generator_found = False + break + if no_generator_found: + raise TypeError("x must be a generator of parent") + return self._poly.degree(self._parent._R.gens()[i]) + self._mon[i] + + def has_inverse_of(self, i): + """ + INPUT: + + - ``i`` -- The index of a generator of ``self.parent()`` + + OUTPUT: + + Returns True if ``self`` contains a monomial including the inverse of + ``self.parent().gen(i)``, False otherwise. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f.has_inverse_of(0) + False + sage: f.has_inverse_of(1) + True + sage: f.has_inverse_of(2) + True + """ + if (not isinstance(i, (int, Integer))) or (i < 0) or (i >= self._parent.ngens()): + raise TypeError("argument is not the index of a generator") + if self._mon[i] < 0: + self._normalize(i) + if self._mon[i] < 0: + return True + return False + return False + + def has_any_inverse(self): + """ + Return True if ``self`` contains any monomials with a negative exponent, False otherwise. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f.has_any_inverse() + True + sage: g = x^2 + y^2 + sage: g.has_any_inverse() + False + """ + for m in self._mon.nonzero_values(sort=False): + if m < 0: + return True + return False + + def __call__(self, *x, **kwds): + """ + Compute value of ``self`` at ``x``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = x + 2*y + 3*z + sage: f(1,1,1) + 6 + sage: f = x^-1 + y + z + sage: f(0,1,1) + Traceback (most recent call last): + ... + ZeroDivisionError + + TESTS:: + + sage: f = x + 2*y + 3*z + sage: f(2) + Traceback (most recent call last): + ... + TypeError: number of arguments does not match the number of generators in parent + sage: f(2,0) + Traceback (most recent call last): + ... + TypeError: number of arguments does not match the number of generators in parent + sage: f( (1,1,1) ) + 6 + """ + if kwds: + f = self.subs(**kwds) + if x: # More than 1 non-keyword argument + return f(*x) + else: + return f + + cdef int l = len(x) + + if l == 1 and isinstance(x[0], (tuple, list)): + x = x[0] + l = len(x) + + if l != self._parent.ngens(): + raise TypeError("number of arguments does not match the number" + " of generators in parent") + + #Check to make sure that we aren't dividing by zero + cdef Py_ssize_t m + for m in range(l): + if x[m] == 0: + if self.has_inverse_of(m): + raise ZeroDivisionError + + ans = self._poly(*x) + if ans: + for m in self._mon.nonzero_positions(): + ans *= x[m]**self._mon[m] + + return ans + + def subs(self, in_dict=None, **kwds): + """ + Substitute some variables in this Laurent polynomial. + + Variable/value pairs for the substitution may be given + as a dictionary or via keyword-value pairs. If both are + present, the latter take precedence. + + INPUT: + + - ``in_dict`` -- dictionary (optional) + + - ``**kwargs`` -- keyword arguments + + OUTPUT: + + A Laurent polynomial. + + EXAMPLES:: + + sage: L.<x, y, z> = LaurentPolynomialRing(QQ) + sage: f = x + 2*y + 3*z + sage: f.subs(x=1) + 2*y + 3*z + 1 + sage: f.subs(y=1) + x + 3*z + 2 + sage: f.subs(z=1) + x + 2*y + 3 + sage: f.subs(x=1, y=1, z=1) + 6 + + sage: f = x^-1 + sage: f.subs(x=2) + 1/2 + sage: f.subs({x: 2}) + 1/2 + + sage: f = x + 2*y + 3*z + sage: f.subs({x: 1, y: 1, z: 1}) + 6 + sage: f.substitute(x=1, y=1, z=1) + 6 + + TESTS:: + + sage: f = x + 2*y + 3*z + sage: f(q=10) + x + 2*y + 3*z + + sage: x.subs({x: 2}, x=1) + 1 + """ + cdef list variables = list(self._parent.gens()) + cdef Py_ssize_t i + for i in range(len(variables)): + if str(variables[i]) in kwds: + variables[i] = kwds[str(variables[i])] + elif in_dict and variables[i] in in_dict: + variables[i] = in_dict[variables[i]] + return self(tuple(variables)) + + def is_constant(self): + r""" + Return whether this Laurent polynomial is constant. + + EXAMPLES:: + + sage: L.<a, b> = LaurentPolynomialRing(QQ) + sage: L(0).is_constant() + True + sage: L(42).is_constant() + True + sage: a.is_constant() + False + sage: (1/b).is_constant() + False + """ + return (self._mon == ETuple({}, int(self._parent.ngens())) and + self._poly.is_constant()) + + def _symbolic_(self, R): + """ + EXAMPLES:: + + sage: R.<x,y> = LaurentPolynomialRing(QQ) + sage: f = x^3 + y/x + sage: g = f._symbolic_(SR); g # optional - sage.symbolic + (x^4 + y)/x + sage: g(x=2, y=2) # optional - sage.symbolic + 9 + + sage: g = SR(f) # optional - sage.symbolic + sage: g(x=2, y=2) # optional - sage.symbolic + 9 + """ + d = {repr(g): R.var(g) for g in self._parent.gens()} + return self.subs(**d) + + def derivative(self, *args): + r""" + The formal derivative of this Laurent polynomial, with respect + to variables supplied in args. + + Multiple variables and iteration counts may be supplied; see + documentation for the global :func:`derivative` function for more + details. + + .. SEEALSO:: + + :meth:`_derivative` + + EXAMPLES:: + + sage: R = LaurentPolynomialRing(ZZ,'x, y') + sage: x, y = R.gens() + sage: t = x**4*y + x*y + y + x**(-1) + y**(-3) + sage: t.derivative(x, x) + 12*x^2*y + 2*x^-3 + sage: t.derivative(y, 2) + 12*y^-5 + """ + return multi_derivative(self, args) + + # add .diff(), .differentiate() as aliases for .derivative() + diff = differentiate = derivative + + def _derivative(self, var=None): + """ + Computes formal derivative of this Laurent polynomial with + respect to the given variable. + + If var is among the generators of this ring, the derivative + is with respect to the generator. Otherwise, ``_derivative(var)`` is called + recursively for each coefficient of this polynomial. + + .. SEEALSO:: :meth:`derivative` + + EXAMPLES:: + + sage: R = LaurentPolynomialRing(ZZ,'x, y') + sage: x, y = R.gens() + sage: t = x**4*y+x*y+y+x**(-1)+y**(-3) + sage: t._derivative(x) + 4*x^3*y + y - x^-2 + sage: t._derivative(y) + x^4 + x + 1 - 3*y^-4 + + sage: R = LaurentPolynomialRing(QQ['z'],'x') + sage: z = R.base_ring().gen() + sage: x = R.gen() + sage: t = 33*z*x**4+x**(-1) + sage: t._derivative(z) + 33*x^4 + sage: t._derivative(x) + -x^-2 + 132*z*x^3 + """ + if var is None: + raise ValueError("must specify which variable to differentiate " + "with respect to") + P = self._parent + cdef list gens = list(P.gens()) + + # check if var is one of the generators + try: + index = gens.index(var) + except ValueError: + # call _derivative() recursively on coefficients + return P({m: c._derivative(var) + for (m, c) in self.dict().iteritems()}) + + # compute formal derivative with respect to generator + cdef dict d = {} + for m, c in self.dict().iteritems(): + if m[index] != 0: + new_m = [u for u in m] + new_m[index] += -1 + d[ETuple(new_m)] = m[index] * c + return P(d) + + def is_univariate(self): + """ + Return ``True`` if this is a univariate or constant Laurent polynomial, + and ``False`` otherwise. + + EXAMPLES:: + + sage: R.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = (x^3 + y^-3)*z + sage: f.is_univariate() + False + sage: g = f(1, y, 4) + sage: g.is_univariate() + True + sage: R(1).is_univariate() + True + """ + return len(self.variables()) < 2 + + def univariate_polynomial(self, R=None): + """ + Return a univariate polynomial associated to this + multivariate polynomial. + + INPUT: + + - ``R`` - (default: ``None``) a univariate Laurent polynomial ring + + If this polynomial is not in at most one variable, then a + ``ValueError`` exception is raised. The new polynomial is over + the same base ring as the given ``LaurentPolynomial`` and in the + variable ``x`` if no ring ``R`` is provided. + + EXAMPLES:: + + sage: R.<x, y> = LaurentPolynomialRing(ZZ) + sage: f = 3*x^2 - 2*y^-1 + 7*x^2*y^2 + 5 + sage: f.univariate_polynomial() + Traceback (most recent call last): + ... + TypeError: polynomial must involve at most one variable + sage: g = f(10, y); g + 700*y^2 + 305 - 2*y^-1 + sage: h = g.univariate_polynomial(); h + -2*y^-1 + 305 + 700*y^2 + sage: h.parent() + Univariate Laurent Polynomial Ring in y over Integer Ring + sage: g.univariate_polynomial(LaurentPolynomialRing(QQ,'z')) + -2*z^-1 + 305 + 700*z^2 + + Here's an example with a constant multivariate polynomial:: + + sage: g = R(1) + sage: h = g.univariate_polynomial(); h + 1 + sage: h.parent() + Univariate Laurent Polynomial Ring in x over Integer Ring + """ + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + v = self.variables() + if len(v) > 1: + raise TypeError("polynomial must involve at most one variable") + elif len(v) == 1: + x = v[0] + i = self._parent.gens().index(x) + x = str(x) + else: + x = 'x' + i = 0 + + #construct ring if none + if R is None: + R = LaurentPolynomialRing(self.base_ring(), x) + + return R({m[i]: c for m,c in self.dict().iteritems()}) + + def factor(self): + """ + Return a Laurent monomial (the unit part of the factorization) and a factored multi-polynomial. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: f = 4*x^7*z^-1 + 3*x^3*y + 2*x^4*z^-2 + x^6*y^-7 + sage: f.factor() + (x^3*y^-7*z^-2) * (4*x^4*y^7*z + 3*y^8*z^2 + 2*x*y^7 + x^3*z^2) + + TESTS: + + Tests for :trac:`29173`:: + + sage: L.<a, b> = LaurentPolynomialRing(ZZ, 'a, b') + sage: (a*b + a + b + 1).factor() + (b + 1) * (a + 1) + sage: ((a^-1)*(a*b + a + b + 1)).factor() + (a^-1) * (b + 1) * (a + 1) + sage: L(-12).factor() + -1 * 2^2 * 3 + """ + pf = self._poly.factor() + + if self._poly.degree() == 0: + # Factorization is broken for polynomials, see + # https://github.com/sagemath/sage/issues/20214 + return pf + + u = self.parent(pf.unit()) + + cdef tuple g = <tuple> self._parent.gens() + for i in self._mon.nonzero_positions(): + u *= g[i] ** self._mon[i] + + cdef list f = [] + cdef dict d + for t in pf: + d = <dict> (t[0].dict()) + if len(d) == 1: # monomials are units + u *= self.parent(d) ** t[1] + else: + f.append((self.parent(d), t[1])) + + return Factorization(f, unit=u) + + def is_square(self, root=False): + r""" + Test whether this Laurent polynomial is a square. + + INPUT: + + - ``root`` - boolean (default ``False``) - if set to ``True`` + then return a pair ``(True, sqrt)`` with ``sqrt`` a square + root of this Laurent polynomial when it exists or + ``(False, None)``. + + EXAMPLES:: + + sage: L.<x,y,z> = LaurentPolynomialRing(QQ) + sage: p = 1 + x*y + z^-3 + sage: (p**2).is_square() + True + sage: (p**2).is_square(root=True) + (True, x*y + 1 + z^-3) + + sage: x.is_square() + False + sage: x.is_square(root=True) + (False, None) + + sage: (x**-4 * (1 + z)).is_square(root=False) + False + sage: (x**-4 * (1 + z)).is_square(root=True) + (False, None) + """ + self._normalize() + if not self._mon.is_multiple_of(2): + return (False, None) if root else False + + cdef LaurentPolynomial_mpair ans + + if not root: + return self._poly.is_square(root=False) + else: + (pans, root) = self._poly.is_square(root=True) + if not pans: + return (False, None) + + mon = self._mon.escalar_div(2) + ans = self._new_c() + ans._mon = mon + ans._poly = root + return (True, ans) + + cpdef rescale_vars(self, dict d, h=None, new_ring=None): + r""" + Rescale variables in a Laurent polynomial. + + INPUT: + + - ``d`` -- a ``dict`` whose keys are the generator indices + and values are the coefficients; so a pair ``(i, v)`` + means `x_i \mapsto v x_i` + - ``h`` -- (optional) a map to be applied to coefficients + done after rescaling + - ``new_ring`` -- (optional) a new ring to map the result into + + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) + sage: p = x^-2*y + x*y^-2 + sage: p.rescale_vars({0: 2, 1: 3}) + 2/9*x*y^-2 + 3/4*x^-2*y + sage: F = GF(2) # optional - sage.rings.finite_rings + sage: p.rescale_vars({0: 3, 1: 7}, new_ring=L.change_ring(F)) # optional - sage.rings.finite_rings + x*y^-2 + x^-2*y + + Test for :trac:`30331`:: + + sage: F.<z> = CyclotomicField(3) # optional - sage.rings.number_field + sage: p.rescale_vars({0: 2, 1: z}, new_ring=L.change_ring(F)) # optional - sage.rings.number_field + 2*z*x*y^-2 + 1/4*z*x^-2*y + """ + cdef int i + cdef dict df + cdef ETuple v + cdef LaurentPolynomial_mpair ans + + if self._prod is None: + self._compute_polydict() + + df = dict(self._prod.__repn) # This makes a copy for us to manipulate + if new_ring is None: + R = self._parent._base + else: + R = new_ring._base + if h is None: + for v in df: + val = df[v] + for i in d: + val *= d[i]**v[i] + df[v] = val + else: + for v in df: + val = df[v] + for i in d: + val *= d[i]**v[i] + df[v] = R(h(val)) + + ans = <LaurentPolynomial_mpair> self._new_c() + ans._prod = PolyDict(df) + ans._mon = self._mon + if new_ring is None: + S = self._poly._parent + else: + S = self._poly._parent.change_ring(R) + ans._poly = <MPolynomial> S({v.esub(ans._mon): df[v] for v in df}) + if new_ring is not None: + return new_ring(ans) + return ans + + cpdef toric_coordinate_change(self, M, h=None, new_ring=None): + r""" + Apply a matrix to the exponents in a Laurent polynomial. + + For efficiency, we implement this directly, rather than as a substitution. + + The optional argument ``h`` is a map to be applied to coefficients. + + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) + sage: p = 2*x^2 + y - x*y + sage: p.toric_coordinate_change(Matrix([[1,-3], [1,1]])) + 2*x^2*y^2 - x^-2*y^2 + x^-3*y + sage: F = GF(2) # optional - sage.rings.finite_rings + sage: p.toric_coordinate_change(Matrix([[1,-3], [1,1]]), # optional - sage.rings.finite_rings + ....: new_ring=L.change_ring(F)) + x^-2*y^2 + x^-3*y + + """ + cdef int n, i, j, x + cdef dict d, dr + cdef ETuple v + cdef LaurentPolynomial_mpair ans + cdef list L, mon, exp + cdef Matrix mat = M + + n = self._parent.ngens() + if mat.dimensions() != (n, n): + raise ValueError("the matrix M must be a {k} x {k} matrix".format(k=n)) + + if not self: + if new_ring is None: + return self._parent.zero() + else: + return new_ring.zero() + + if self._prod is None: + self._compute_polydict() + + d = self._prod.__repn + dr = {} + mon = [0] * n + for v in d: + # Make a copy of mon as this might be faster than creating the data from scratch. + # We will set every entry, so no need to clear the data. + exp = list(mon) + for j in range(n): + x = 0 + for i in range(n): + if not mat.get_is_zero_unsafe(j, i): + x += (<int> v[i]) * int(mat.get_unsafe(j, i)) + if x < (<int> mon[j]): + mon[j] = x + exp[j] = x + dr[ETuple(exp)] = d[v] + + if h is not None: + for v in dr: + dr[v] = self._parent._base(h(dr[v])) + + ans = <LaurentPolynomial_mpair> self._new_c() + ans._prod = PolyDict(dr) + ans._mon = ETuple(mon) + ans._poly = <MPolynomial> self._poly._parent({v.esub(ans._mon): dr[v] for v in dr}) + if new_ring is not None: + return new_ring(ans) + return ans + + cpdef toric_substitute(self, v, v1, a, h=None, new_ring=None): + r""" + Perform a single-variable substitution up to a toric coordinate change. + + The optional argument ``h`` is a map to be applied to coefficients. + + EXAMPLES:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) + sage: p = x + y + sage: p.toric_substitute((2,3), (-1,1), 2) + 1/2*x^3*y^3 + 2*x^-2*y^-2 + sage: F = GF(5) + sage: p.toric_substitute((2,3), (-1,1), 2, new_ring=L.change_ring(F)) + 3*x^3*y^3 + 2*x^-2*y^-2 + + TESTS: + + Tests for :trac:`30331`:: + + sage: L.<x,y> = LaurentPolynomialRing(QQ, 2) + sage: p = x + y + sage: F.<z> = CyclotomicField(3) + sage: p.toric_substitute((2,3), (-1,1), z, new_ring=L.change_ring(F)) + (-z - 1)*x^3*y^3 + z*x^-2*y^-2 + + sage: P.<x> = LaurentPolynomialRing(QQ, 1) + sage: u = x - 1 + sage: v = u.toric_substitute((-1,), (-1,), 1) + sage: v.is_zero() + True + """ + cdef dict d, dr + cdef ETuple ve, v1e, w, w1, mon + cdef LaurentPolynomial_mpair ans + cdef int t + + if self._prod is None: + self._compute_polydict() + + d = self._prod.__repn + dr = {} + ve = ETuple(v) + v1e = ETuple(v1) + mon = self._mon + if h is not None: + d = dict(d) # Make a copy so we can manipulate it + for w in d: + d[w] = h(d[w]) + for w in d: + x = d[w] + t = w.dotprod(v1e) + w1 = w.eadd_scaled(ve, -t) + if w1 in dr: + dr[w1] += x * a**t + else: + dr[w1] = x * a**t + mon = mon.emin(w1) + for v in tuple(dr.keys()): + if not dr[v]: + del dr[v] + + if new_ring is None: + S = self._poly._parent + else: + S = self._poly._parent.change_ring(new_ring._base) + ans = <LaurentPolynomial_mpair> self._new_c() + ans._prod = PolyDict(dr) + ans._mon = mon + ans._poly = <MPolynomial> S({v.esub(ans._mon): dr[v] for v in dr}) + if new_ring is not None: + return new_ring(ans) + return ans From f094cdc6db1baba4bdc0146e976cad0447968112 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe <mkoeppe@math.ucdavis.edu> Date: Wed, 19 Apr 2023 20:42:19 -0700 Subject: [PATCH 3/8] sage.data_structures.stream, sage.rings.lazy_series: Modularization fixes --- src/sage/data_structures/stream.py | 4 +- src/sage/rings/lazy_series.py | 3 +- src/sage/rings/lazy_series_ring.py | 251 +++++++++++++++++------------ 3 files changed, 149 insertions(+), 109 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 4bffa84bfc9..b11a27318f5 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -99,10 +99,12 @@ from sage.arith.misc import divisors from sage.misc.misc_c import prod from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.lazy_import import lazy_import from sage.combinat.integer_vector_weighted import iterator_fast as wt_int_vec_iter -from sage.combinat.sf.sfa import _variables_recursive, _raise_variables from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis +lazy_import('sage.combinat.sf.sfa', ['_variables_recursive', '_raise_variables']) + class Stream(): """ diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index f31488d5354..581ceaac1ea 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -211,11 +211,10 @@ from sage.structure.element import Element, parent from sage.structure.richcmp import op_EQ, op_NE -from sage.functions.other import factorial from sage.misc.misc_c import prod from sage.arith.power import generic_power from sage.arith.functions import lcm -from sage.arith.misc import divisors, moebius +from sage.arith.misc import divisors, factorial, moebius from sage.combinat.partition import Partition, Partitions from sage.misc.derivative import derivative_parse from sage.categories.integral_domains import IntegralDomains diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index d8ba728a61b..89d4cd39127 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -52,6 +52,7 @@ CompleteDiscreteValuationRings) from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing @@ -64,7 +65,6 @@ LazySymmetricFunction, LazyDirichletSeries) from sage.structure.global_options import GlobalOptions -from sage.symbolic.ring import SR from sage.data_structures.stream import ( Stream_zero, @@ -155,10 +155,10 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No If ``x`` can be converted into an element of the underlying Laurent polynomial ring, we do this:: - sage: L = LazyLaurentSeriesRing(GF(2), 'z') - sage: L(2) + sage: L = LazyLaurentSeriesRing(GF(2), 'z') # optional - sage.rings.finite_rings + sage: L(2) # optional - sage.rings.finite_rings 0 - sage: L(3) + sage: L(3) # optional - sage.rings.finite_rings 1 In particular, ``x`` can be a Laurent polynomial:: @@ -288,21 +288,21 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No Converting various series from a univariate power series:: - sage: L = LazyLaurentSeriesRing(GF(2), 'z') - sage: R = LazyPowerSeriesRing(ZZ, 'z') - sage: L.has_coerce_map_from(R) + sage: L = LazyLaurentSeriesRing(GF(2), 'z') # optional - sage.rings.finite_rings + sage: R = LazyPowerSeriesRing(ZZ, 'z') # optional - sage.rings.finite_rings + sage: L.has_coerce_map_from(R) # optional - sage.rings.finite_rings True - sage: L(R(lambda n: n)) + sage: L(R(lambda n: n)) # optional - sage.rings.finite_rings z + z^3 + z^5 + z^7 + O(z^8) - sage: L(R([2,4,6])) == L.zero() + sage: L(R([2,4,6])) == L.zero() # optional - sage.rings.finite_rings True - sage: L(R([2,4,6], valuation=2, constant=4)) == L.zero() + sage: L(R([2,4,6], valuation=2, constant=4)) == L.zero() # optional - sage.rings.finite_rings True - sage: L(R([2,4,6], valuation=2, constant=5)) + sage: L(R([2,4,6], valuation=2, constant=5)) # optional - sage.rings.finite_rings z^5 + z^6 + z^7 + O(z^8) - sage: L(R([2,3,4], valuation=2, constant=4)) + sage: L(R([2,3,4], valuation=2, constant=4)) # optional - sage.rings.finite_rings z^3 - sage: L(R([2,3,4], valuation=2, constant=5)) + sage: L(R([2,3,4], valuation=2, constant=5)) # optional - sage.rings.finite_rings z^3 + z^5 + z^6 + z^7 + O(z^8) Can only convert from known to be constant multivariate power series:: @@ -760,14 +760,14 @@ def characteristic(self): sage: L.characteristic() 0 - sage: R.<w> = LazyLaurentSeriesRing(GF(11)); R + sage: R.<w> = LazyLaurentSeriesRing(GF(11)); R # optional - sage.rings.finite_rings Lazy Laurent Series Ring in w over Finite Field of size 11 - sage: R.characteristic() + sage: R.characteristic() # optional - sage.rings.finite_rings 11 - sage: R.<x, y> = LazyPowerSeriesRing(GF(7)); R + sage: R.<x, y> = LazyPowerSeriesRing(GF(7)); R # optional - sage.rings.finite_rings Multivariate Lazy Taylor Series Ring in x, y over Finite Field of size 7 - sage: R.characteristic() + sage: R.characteristic() # optional - sage.rings.finite_rings 7 sage: L = LazyDirichletSeriesRing(ZZ, "s") @@ -782,13 +782,13 @@ def _coerce_map_from_(self, S): EXAMPLES:: - sage: L = LazyLaurentSeriesRing(GF(2), 'z') - sage: L.has_coerce_map_from(ZZ) + sage: L = LazyLaurentSeriesRing(GF(2), 'z') # optional - sage.rings.finite_rings + sage: L.has_coerce_map_from(ZZ) # optional - sage.rings.finite_rings True - sage: L.has_coerce_map_from(GF(2)) + sage: L.has_coerce_map_from(GF(2)) # optional - sage.rings.finite_rings True sage: R = LazyPowerSeriesRing(ZZ, 'z') - sage: L.has_coerce_map_from(R) + sage: L.has_coerce_map_from(R) # optional - sage.rings.finite_rings True sage: L = LazyLaurentSeriesRing(QQ, 'z') @@ -802,17 +802,17 @@ def _coerce_map_from_(self, S): sage: L.has_coerce_map_from(R) False - sage: L = LazyPowerSeriesRing(GF(2), 'z') - sage: L.has_coerce_map_from(ZZ) + sage: L = LazyPowerSeriesRing(GF(2), 'z') # optional - sage.rings.finite_rings + sage: L.has_coerce_map_from(ZZ) # optional - sage.rings.finite_rings True - sage: L.has_coerce_map_from(GF(2)) + sage: L.has_coerce_map_from(GF(2)) # optional - sage.rings.finite_rings True - sage: s = SymmetricFunctions(GF(2)).s() - sage: L = LazySymmetricFunctions(s) - sage: L.has_coerce_map_from(ZZ) + sage: s = SymmetricFunctions(GF(2)).s() # optional - sage.rings.finite_rings + sage: L = LazySymmetricFunctions(s) # optional - sage.rings.finite_rings + sage: L.has_coerce_map_from(ZZ) # optional - sage.rings.finite_rings True - sage: L.has_coerce_map_from(GF(2)) + sage: L.has_coerce_map_from(GF(2)) # optional - sage.rings.finite_rings True """ if self.base_ring().has_coerce_map_from(S): @@ -845,11 +845,14 @@ def _coerce_map_from_base_ring(self): sage: L = LazyDirichletSeriesRing(QQ, 'z') sage: phi = L._coerce_map_from_base_ring() - sage: phi(2) + sage: m = phi(2) + sage: m # optional - sage.symbolic 2 - sage: phi(2, valuation=2) + sage: m = phi(2, valuation=2) + sage: m # optional - sage.symbolic 2/2^z - sage: phi(2, valuation=2, constant=4) + sage: m = phi(2, valuation=2, constant=4) + sage: m # optional - sage.symbolic 2/2^z + 4/3^z + 4/4^z + 4/5^z + O(1/(6^z)) """ # Return a DefaultConvertMap_unique; this can pass additional @@ -1048,12 +1051,12 @@ class LazyLaurentSeriesRing(LazySeriesRing): Lazy Laurent series ring over a finite field:: - sage: L.<z> = LazyLaurentSeriesRing(GF(3)); L + sage: L.<z> = LazyLaurentSeriesRing(GF(3)); L # optional - sage.rings.finite_rings Lazy Laurent Series Ring in z over Finite Field of size 3 - sage: e = 1 / (1 + z) - sage: e.coefficient(100) + sage: e = 1 / (1 + z) # optional - sage.rings.finite_rings + sage: e.coefficient(100) # optional - sage.rings.finite_rings 1 - sage: e.coefficient(100).parent() + sage: e.coefficient(100).parent() # optional - sage.rings.finite_rings Finite Field of size 3 Series can be defined by specifying a coefficient function @@ -1202,14 +1205,14 @@ def __init__(self, base_ring, names, sparse=True, category=None): (euclidean domains and infinite enumerated sets and metric spaces) and infinite sets) - sage: L = LazyLaurentSeriesRing(GF(5), 't') - sage: TestSuite(L).run() + sage: L = LazyLaurentSeriesRing(GF(5), 't') # optional - sage.rings.finite_rings + sage: TestSuite(L).run() # optional - sage.rings.finite_rings - sage: L = LazyLaurentSeriesRing(GF(5)['x'], 't') - sage: TestSuite(L).run() + sage: L = LazyLaurentSeriesRing(GF(5)['x'], 't') # optional - sage.rings.finite_rings + sage: TestSuite(L).run() # optional - sage.rings.finite_rings - sage: L = LazyLaurentSeriesRing(GF(5)['x, y'], 't') - sage: TestSuite(L).run() + sage: L = LazyLaurentSeriesRing(GF(5)['x, y'], 't') # optional - sage.rings.finite_rings + sage: TestSuite(L).run() # optional - sage.rings.finite_rings sage: L = LazyLaurentSeriesRing(Zmod(6), 't') sage: TestSuite(L).run(skip=['_test_revert']) @@ -1252,7 +1255,7 @@ def _repr_(self): EXAMPLES:: - sage: LazyLaurentSeriesRing(GF(2), 'z') + sage: LazyLaurentSeriesRing(GF(2), 'z') # optional - sage.rings.finite_rings Lazy Laurent Series Ring in z over Finite Field of size 2 """ return "Lazy Laurent Series Ring in {} over {}".format(self.variable_name(), self.base_ring()) @@ -1263,8 +1266,8 @@ def _latex_(self): EXAMPLES:: - sage: L = LazyLaurentSeriesRing(GF(2), 'z') - sage: latex(L) + sage: L = LazyLaurentSeriesRing(GF(2), 'z') # optional - sage.rings.finite_rings + sage: latex(L) # optional - sage.rings.finite_rings \Bold{F}_{2} (\!(z)\!) """ from sage.misc.latex import latex @@ -1349,16 +1352,16 @@ def some_elements(self): -2*z^-3 - 2*z^-2 + 4*z^-1 + 11 - z - 34*z^2 - 31*z^3 + O(z^4), 4*z^-2 + z^-1 + z + 4*z^2 + 9*z^3 + 16*z^4 + O(z^5)] - sage: L = LazyLaurentSeriesRing(GF(2), 'z') - sage: L.some_elements()[:7] + sage: L = LazyLaurentSeriesRing(GF(2), 'z') # optional - sage.rings.finite_rings + sage: L.some_elements()[:7] # optional - sage.rings.finite_rings [0, 1, z, z^-4 + z^-3 + z^2 + z^3, z^-2, 1 + z + z^3 + z^4 + z^6 + O(z^7), z^-1 + z + z^3 + O(z^5)] - sage: L = LazyLaurentSeriesRing(GF(3), 'z') - sage: L.some_elements()[:7] + sage: L = LazyLaurentSeriesRing(GF(3), 'z') # optional - sage.rings.finite_rings + sage: L.some_elements()[:7] # optional - sage.rings.finite_rings [0, 1, z, z^-3 + z^-1 + 2 + z + z^2 + z^3, z^-2, @@ -1666,11 +1669,11 @@ def __init__(self, base_ring, names, sparse=True, category=None): sage: L = LazyPowerSeriesRing(QQ, 's, t') sage: TestSuite(L).run(skip="_test_fraction_field") - sage: L = LazyPowerSeriesRing(GF(5), 't') - sage: TestSuite(L).run() + sage: L = LazyPowerSeriesRing(GF(5), 't') # optional - sage.rings.finite_rings + sage: TestSuite(L).run() # optional - sage.rings.finite_rings - sage: L = LazyPowerSeriesRing(GF(5), 's, t') - sage: TestSuite(L).run(skip=['_test_fraction_field']) + sage: L = LazyPowerSeriesRing(GF(5), 's, t') # optional - sage.rings.finite_rings + sage: TestSuite(L).run(skip=['_test_fraction_field']) # optional - sage.rings.finite_rings sage: L = LazyPowerSeriesRing(Zmod(6), 't') sage: TestSuite(L).run(skip=['_test_revert']) @@ -1752,7 +1755,7 @@ def _repr_(self): EXAMPLES:: - sage: LazyPowerSeriesRing(GF(2), 'z') + sage: LazyPowerSeriesRing(GF(2), 'z') # optional - sage.rings.finite_rings Lazy Taylor Series Ring in z over Finite Field of size 2 """ BR = self.base_ring() @@ -1767,8 +1770,8 @@ def _latex_(self): EXAMPLES:: - sage: L = LazyPowerSeriesRing(GF(2), 'z') - sage: latex(L) + sage: L = LazyPowerSeriesRing(GF(2), 'z') # optional - sage.rings.finite_rings + sage: latex(L) # optional - sage.rings.finite_rings \Bold{F}_{2} [\![z]\!] """ from sage.misc.latex import latex @@ -1866,10 +1869,10 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No EXAMPLES:: - sage: L = LazyPowerSeriesRing(GF(2), 'z') - sage: L(2) + sage: L = LazyPowerSeriesRing(GF(2), 'z') # optional - sage.rings.finite_rings + sage: L(2) # optional - sage.rings.finite_rings 0 - sage: L(3) + sage: L(3) # optional - sage.rings.finite_rings 1 sage: L = LazyPowerSeriesRing(ZZ, 'z') @@ -1883,7 +1886,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: X.valuation() 2 - sage: e = L(lambda n: n+1); e + sage: e = L(lambda n: n + 1); e 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) sage: f = e^-1; f 1 - 2*z + z^2 + O(z^7) @@ -2188,15 +2191,15 @@ def some_elements(self): 1 + z - 2*z^2 - 7*z^3 - z^4 + 20*z^5 + 23*z^6 + O(z^7), z + 4*z^2 + 9*z^3 + 16*z^4 + 25*z^5 + 36*z^6 + O(z^7)] - sage: L = LazyPowerSeriesRing(GF(3)["q"], 'z') - sage: L.some_elements()[:6] + sage: L = LazyPowerSeriesRing(GF(3)["q"], 'z') # optional - sage.rings.finite_rings + sage: L.some_elements()[:6] # optional - sage.rings.finite_rings [0, 1, z + q*z^2 + q*z^3 + q*z^4 + O(z^5), z + z^2 + z^3, 1 + z + z^2 + 2*z^3 + 2*z^4 + 2*z^5 + O(z^6), z + z^2 + z^4 + z^5 + O(z^7)] - sage: L = LazyPowerSeriesRing(GF(3), 'q, t') - sage: L.some_elements()[:6] + sage: L = LazyPowerSeriesRing(GF(3), 'q, t') # optional - sage.rings.finite_rings + sage: L.some_elements()[:6] # optional - sage.rings.finite_rings [0, 1, q, q + q^2 + q^3, 1 + q + q^2 + (-q^3) + (-q^4) + (-q^5) + (-q^6) + O(q,t)^7, @@ -2274,9 +2277,9 @@ def __init__(self, basis, sparse=True, category=None): sage: L = LazySymmetricFunctions(s) sage: TestSuite(L).run() - sage: p = SymmetricFunctions(GF(5)).p() - sage: L = LazySymmetricFunctions(p) - sage: TestSuite(L).run() + sage: p = SymmetricFunctions(GF(5)).p() # optional - sage.rings.finite_rings + sage: L = LazySymmetricFunctions(p) # optional - sage.rings.finite_rings + sage: TestSuite(L).run() # optional - sage.rings.finite_rings Reversion will only work when the base ring is a field:: @@ -2342,8 +2345,8 @@ def _repr_(self): EXAMPLES:: - sage: s = SymmetricFunctions(GF(2)).s() - sage: LazySymmetricFunctions(s) + sage: s = SymmetricFunctions(GF(2)).s() # optional - sage.rings.finite_rings + sage: LazySymmetricFunctions(s) # optional - sage.rings.finite_rings Lazy completion of Symmetric Functions over Finite Field of size 2 in the Schur basis """ return "Lazy completion of {}".format(self._laurent_poly_ring) @@ -2354,9 +2357,9 @@ def _latex_(self): EXAMPLES:: - sage: s = SymmetricFunctions(GF(2)).s() - sage: L = LazySymmetricFunctions(s) - sage: latex(L) + sage: s = SymmetricFunctions(GF(2)).s() # optional - sage.rings.finite_rings + sage: L = LazySymmetricFunctions(s) # optional - sage.rings.finite_rings + sage: latex(L) # optional - sage.rings.finite_rings \text{\texttt{Symmetric{ }Functions{ }over{ }Finite{ }Field{ }of{ }size{ }2{ }in{ }the{ }Schur{ }basis}} """ from sage.misc.latex import latex @@ -2393,11 +2396,11 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No EXAMPLES:: - sage: m = SymmetricFunctions(GF(2)).m() - sage: L = LazySymmetricFunctions(m) - sage: L(2) + sage: m = SymmetricFunctions(GF(2)).m() # optional - sage.rings.finite_rings + sage: L = LazySymmetricFunctions(m) # optional - sage.rings.finite_rings + sage: L(2) # optional - sage.rings.finite_rings 0 - sage: L(3) + sage: L(3) # optional - sage.rings.finite_rings m[] sage: m = SymmetricFunctions(ZZ).m() @@ -2577,9 +2580,9 @@ def some_elements(self): EXAMPLES:: - sage: m = SymmetricFunctions(GF(5)).m() - sage: L = LazySymmetricFunctions(m) - sage: L.some_elements()[:5] + sage: m = SymmetricFunctions(GF(5)).m() # optional - sage.rings.finite_rings + sage: L = LazySymmetricFunctions(m) # optional - sage.rings.finite_rings + sage: L.some_elements()[:5] # optional - sage.rings.finite_rings [0, m[], 2*m[] + 2*m[1] + 3*m[2], 2*m[1] + 3*m[2], 3*m[] + 2*m[1] + (m[1,1]+m[2]) + (2*m[1,1,1]+m[3]) @@ -2710,6 +2713,24 @@ class LazyDirichletSeriesRing(LazySeriesRing): # Follow the "generic" normalization __classcall_private__ = LazySeriesRing.__classcall_private__ + @lazy_attribute + def _laurent_poly_ring(self): + r""" + Return the symbolic ring. + + .. TODO:: + + It would be good to have something better than the symbolic ring. + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, 't') + sage: L._laurent_poly_ring is SR # optional - sage.symbolic + True + """ + from sage.symbolic.ring import SR + return SR + def __init__(self, base_ring, names, sparse=True, category=None): r""" Initialize the ring. @@ -2733,7 +2754,6 @@ def __init__(self, base_ring, names, sparse=True, category=None): self._sparse = sparse self._minimal_valuation = 1 self._arity = 1 - self._laurent_poly_ring = SR # TODO: it would be good to have something better than the symbolic ring self._internal_poly_ring = PolynomialRing(base_ring, names, sparse=sparse) category = Algebras(base_ring.category()) @@ -2751,7 +2771,7 @@ def _repr_(self): EXAMPLES:: - sage: LazyDirichletSeriesRing(QQbar, 'z') + sage: LazyDirichletSeriesRing(QQbar, 'z') # optional - sage.rings.number_field Lazy Dirichlet Series Ring in z over Algebraic Field """ return "Lazy Dirichlet Series Ring in {} over {}".format(self.variable_name(), self.base_ring()) @@ -2764,9 +2784,9 @@ def one(self): EXAMPLES:: sage: L = LazyDirichletSeriesRing(ZZ, 'z') - sage: L.one() + sage: L.one() # optional - sage.symbolic 1 - sage: ~L.one() + sage: ~L.one() # optional - sage.symbolic 1 + O(1/(8^z)) """ R = self.base_ring() @@ -2804,25 +2824,32 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No EXAMPLES:: sage: L = LazyDirichletSeriesRing(ZZ, 'z') - sage: L(3) + sage: R = L(3) + sage: R # optional - sage.symbolic 3 - sage: L(lambda i: i, constant=1, degree=6) + sage: S = L(lambda i: i, constant=1, degree=6) + sage: S # optional - sage.symbolic 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 1/(6^z) + 1/(7^z) + 1/(8^z) + O(1/(9^z)) - sage: X = L(constant=5, degree=3); X + sage: X = L(constant=5, degree=3) + sage: X # optional - sage.symbolic 5/3^z + 5/4^z + 5/5^z + O(1/(6^z)) sage: X.valuation() log(3) - sage: e = L(moebius); e + sage: e = L(moebius) + sage: e # optional - sage.symbolic 1 - 1/(2^z) - 1/(3^z) - 1/(5^z) + 1/(6^z) - 1/(7^z) + O(1/(8^z)) - sage: L([0], constant=1) + sage: T = L([0], constant=1) + sage: T # optional - sage.symbolic 1/(2^z) + 1/(3^z) + 1/(4^z) + O(1/(5^z)) - sage: L(constant=1) + sage: U = L(constant=1) + sage: U # optional - sage.symbolic 1 + 1/(2^z) + 1/(3^z) + O(1/(4^z)) - sage: L(lambda i: i, valuation=3) + sage: V = L(lambda i: i, valuation=3) + sage: V # optional - sage.symbolic 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + 8/8^z + 9/9^z + O(1/(10^z)) Alternatively, ``x`` can be a list of elements of the base ring. @@ -2831,37 +2858,45 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No may be just an element of the base ring instead of a tuple or can be simply omitted if it is zero:: - sage: f = L([1,2,3,4], 4); f + sage: f = L([1,2,3,4], 4) + sage: f # optional - sage.symbolic 1/(4^z) + 2/5^z + 3/6^z + 4/7^z - sage: g = L([1,3,5,7,9], 6, constant=-1); g - 1/(6^z) + 3/7^z + 5/8^z + 7/9^z + 9/10^z - 1/(11^z) - 1/(12^z) - 1/(13^z) + O(1/(14^z)) + sage: g = L([1,3,5,7,9], 6, constant=-1) + sage: g # optional - sage.symbolic + 1/(6^z) + 3/7^z + 5/8^z + 7/9^z + 9/10^z - 1/(11^z) - 1/(12^z) + - 1/(13^z) + O(1/(14^z)) TESTS:: - sage: L = LazyDirichletSeriesRing(GF(2), 'z') + sage: L = LazyDirichletSeriesRing(GF(2), 'z') # optional - sage.rings.finite_rings Traceback (most recent call last): ... ValueError: positive characteristic not allowed for Dirichlet series sage: L.<z> = LazyLaurentSeriesRing(QQ) sage: D = LazyDirichletSeriesRing(QQ, 't') - sage: D(L.one()) + sage: d = D(L.one()) + sage: d # optional - sage.symbolic 1 + 1/(2^t) + 1/(3^t) + 1/(4^t) + 1/(5^t) + 1/(6^t) + 1/(7^t) + O(1/(8^t)) sage: R.<z> = LaurentPolynomialRing(QQ) sage: D = LazyDirichletSeriesRing(QQ, 't') - sage: D(coefficients=z+z^2) + sage: dd = D(coefficients=z + z^2) + sage: dd # optional - sage.symbolic 2 + 6/2^t + 12/3^t + 20/4^t + 30/5^t + 42/6^t + 56/7^t + O(1/(8^t)) sage: s = D(lambda n: n) - sage: D(s, valuation=2) + sage: d2 = D(s, valuation=2) + sage: d2 # optional - sage.symbolic 1/(2^t) + 2/3^t + 3/4^t + 4/5^t + 5/6^t + 6/7^t + 7/8^t + O(1/(9^t)) sage: Ds = LazyDirichletSeriesRing(ZZ, 's') - sage: m = Ds(moebius, valuation=2); m + sage: m = Ds(moebius, valuation=2) + sage: m # optional - sage.symbolic -1/(2^s) - 1/(3^s) - 1/(5^s) + 1/(6^s) - 1/(7^s) + O(1/(9^s)) sage: D = LazyDirichletSeriesRing(QQ, 't') - sage: D(m) + sage: dm = D(m) + sage: dm # optional - sage.symbolic -1/(2^t) - 1/(3^t) - 1/(5^t) + 1/(6^t) - 1/(7^t) + O(1/(9^t)) """ if isinstance(x, (list, tuple)): @@ -2906,7 +2941,8 @@ def _an_element_(self): EXAMPLES:: sage: L = LazyDirichletSeriesRing(ZZ, 'z') - sage: L.an_element() + sage: m = L.an_element() + sage: m # optional - sage.symbolic 1/(4^z) + 1/(5^z) + 1/(6^z) + O(1/(7^z)) """ c = self.base_ring().an_element() @@ -2919,7 +2955,8 @@ def some_elements(self): EXAMPLES:: sage: L = LazyDirichletSeriesRing(ZZ, 'z') - sage: L.some_elements() + sage: l = L.some_elements() + sage: l # optional - sage.symbolic [0, 1, 1/(4^z) + 1/(5^z) + 1/(6^z) + O(1/(7^z)), 1/(2^z) - 1/(3^z) + 2/4^z - 2/5^z + 3/6^z - 3/7^z + 4/8^z - 4/9^z, @@ -2927,7 +2964,8 @@ def some_elements(self): 1 + 4/2^z + 9/3^z + 16/4^z + 25/5^z + 36/6^z + 49/7^z + O(1/(8^z))] sage: L = LazyDirichletSeriesRing(QQ, 'z') - sage: L.some_elements() + sage: l = L.some_elements() + sage: l # optional - sage.symbolic [0, 1, 1/2/4^z + 1/2/5^z + 1/2/6^z + O(1/(7^z)), 1/2 - 1/2/2^z + 2/3^z - 2/4^z + 1/(6^z) - 1/(7^z) + 42/8^z + 2/3/9^z, @@ -2949,7 +2987,8 @@ def _monomial(self, c, n): EXAMPLES:: sage: L = LazyDirichletSeriesRing(ZZ, 'z') - sage: L._monomial(5, 3) + sage: m = L._monomial(5, 3) + sage: m # optional - sage.symbolic 5/3^z """ try: @@ -2969,11 +3008,11 @@ def _skip_leading_zeros(iterator): sage: [x for x, _ in zip(_skip_leading_zeros(it), range(10))] [10, 11, 12, 13, 14, 15, 16, 17, 18, 19] - sage: it = map(GF(3), NN) - sage: [x for x, _ in zip(it, range(10))] + sage: it = map(GF(3), NN) # optional - sage.rings.finite_rings + sage: [x for x, _ in zip(it, range(10))] # optional - sage.rings.finite_rings [0, 1, 2, 0, 1, 2, 0, 1, 2, 0] - sage: it = map(GF(3), NN) - sage: [x for x, _ in zip(_skip_leading_zeros(it), range(10))] + sage: it = map(GF(3), NN) # optional - sage.rings.finite_rings + sage: [x for x, _ in zip(_skip_leading_zeros(it), range(10))] # optional - sage.rings.finite_rings [1, 2, 0, 1, 2, 0, 1, 2, 0, 1] """ while True: From eaef6e6d348347230589c1dbc9caa6907365fa3a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe <mkoeppe@math.ucdavis.edu> Date: Sun, 23 Apr 2023 15:56:24 -0700 Subject: [PATCH 4/8] Fix imports --- src/sage/rings/big_oh.py | 21 ++++++++----------- .../polynomial/laurent_polynomial_mpair.pxd | 1 + .../polynomial/laurent_polynomial_mpair.pyx | 3 ++- .../polynomial/laurent_polynomial_ring.py | 6 +++--- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/sage/rings/big_oh.py b/src/sage/rings/big_oh.py index 1df61a39dc0..19d02f94459 100644 --- a/src/sage/rings/big_oh.py +++ b/src/sage/rings/big_oh.py @@ -10,6 +10,10 @@ """ from sage.arith.misc import factor +from sage.misc.lazy_import import lazy_import +lazy_import('sage.rings.padics.factory', ['Qp', 'Zp']) +lazy_import('sage.rings.padics.padic_generic_element', 'pAdicGenericElement') +from sage.rings.polynomial.polynomial_element import Polynomial try: from .laurent_series_ring_element import LaurentSeries @@ -17,20 +21,13 @@ LaurentSeries = () try: - from sage.rings.puiseux_series_ring_element import PuiseuxSeries + from .puiseux_series_ring_element import PuiseuxSeries except ImportError: PuiseuxSeries = () -try: - import sage.rings.padics.factory as padics_factory - from sage.rings.padics.padic_generic_element.padic_generic_element import pAdicGenericElement -except ImportError: - pAdicGenericElement = () - from . import power_series_ring_element from . import integer from . import rational -from sage.rings.polynomial.polynomial_element import Polynomial from . import multi_power_series_ring_element @@ -165,11 +162,11 @@ def O(*x, **kwds): raise ArithmeticError("x must be prime power") p, r = F[0] if r >= 0: - return padics_factory.Zp(p, prec=max(r, 20), - type='capped-rel')(0, absprec=r, **kwds) + return Zp(p, prec=max(r, 20), + type='capped-rel')(0, absprec=r, **kwds) else: - return padics_factory.Qp(p, prec=max(r, 20), - type='capped-rel')(0, absprec=r, **kwds) + return Qp(p, prec=max(r, 20), + type='capped-rel')(0, absprec=r, **kwds) elif isinstance(x, pAdicGenericElement): return x.parent()(0, absprec=x.valuation(), **kwds) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pxd b/src/sage/rings/polynomial/laurent_polynomial_mpair.pxd index eb31593dc77..79f09def6aa 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pxd +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pxd @@ -1,3 +1,4 @@ +from sage.rings.polynomial.laurent_polynomial cimport LaurentPolynomial from sage.rings.polynomial.multi_polynomial cimport MPolynomial from sage.rings.polynomial.polydict cimport ETuple, PolyDict diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index ceb64874f77..70bc5f4e023 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -12,6 +12,7 @@ Elements of multivariate Laurent polynomial rings from sage.rings.integer cimport Integer from sage.categories.map cimport Map +from sage.structure.element cimport CommutativeAlgebraElement, Element, ModuleElement, RingElement from sage.structure.element import is_Element, coerce_binop, parent from sage.structure.factorization import Factorization from sage.misc.derivative import multi_derivative @@ -68,7 +69,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): :: - sage: from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial_mpair + sage: from sage.rings.polynomial.laurent_polynomial_mpair import LaurentPolynomial_mpair sage: LaurentPolynomial_mpair(L, {(1,2): 1/42}, mon=(-3, -3)) 1/42*w^-2*z^-1 diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index f56b911ad3b..e3fb6e0992d 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -43,7 +43,7 @@ # **************************************************************************** from sage.misc.lazy_import import LazyImport -from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial_univariate +from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial, LaurentPolynomial_univariate from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.structure.element import parent @@ -527,7 +527,7 @@ def _element_constructor_(self, x): if isinstance(x, Expression): return x.laurent_polynomial(ring=self) - elif isinstance(x, (LaurentPolynomial_univariate, LaurentPolynomial_mpair)): + elif isinstance(x, LaurentPolynomial): P = x.parent() if set(self.variable_names()) & set(P.variable_names()): if isinstance(x, LaurentPolynomial_univariate): @@ -743,7 +743,7 @@ def _element_constructor_(self, x, mon=None): elif isinstance(x, Expression): return x.laurent_polynomial(ring=self) - elif isinstance(x, (LaurentPolynomial_univariate, LaurentPolynomial_mpair)): + elif isinstance(x, LaurentPolynomial): if self.variable_names() == P.variable_names(): # No special processing needed here; # handled by LaurentPolynomial_mpair.__init__ From cdb4755a1efe82ae7370bbfd3980310a21dafaf3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe <mkoeppe@math.ucdavis.edu> Date: Sun, 23 Apr 2023 16:20:31 -0700 Subject: [PATCH 5/8] src/sage/rings/polynomial/laurent_polynomial_mpair.pyx: Docstring cosmetics --- .../polynomial/laurent_polynomial_mpair.pyx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 70bc5f4e023..4597219b678 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1164,8 +1164,8 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): OUTPUT: - Returns True if ``self`` contains a monomial including the inverse of - ``self.parent().gen(i)``, False otherwise. + Return ``True`` if ``self`` contains a monomial including the inverse of + ``self.parent().gen(i)``, ``False`` otherwise. EXAMPLES:: @@ -1189,7 +1189,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): def has_any_inverse(self): """ - Return True if ``self`` contains any monomials with a negative exponent, False otherwise. + Return ``True`` if ``self`` contains any monomials with a negative exponent, False otherwise. EXAMPLES:: @@ -1279,7 +1279,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): - ``in_dict`` -- dictionary (optional) - - ``**kwargs`` -- keyword arguments + - ``**kwds`` -- keyword arguments OUTPUT: @@ -1395,10 +1395,10 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): def _derivative(self, var=None): """ - Computes formal derivative of this Laurent polynomial with + Compute formal derivative of this Laurent polynomial with respect to the given variable. - If var is among the generators of this ring, the derivative + If ``var`` is among the generators of this ring, the derivative is with respect to the generator. Otherwise, ``_derivative(var)`` is called recursively for each coefficient of this polynomial. @@ -1475,8 +1475,8 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): - ``R`` - (default: ``None``) a univariate Laurent polynomial ring If this polynomial is not in at most one variable, then a - ``ValueError`` exception is raised. The new polynomial is over - the same base ring as the given ``LaurentPolynomial`` and in the + :class:`ValueError` exception is raised. The new polynomial is over + the same base ring as the given :class:`LaurentPolynomial` and in the variable ``x`` if no ring ``R`` is provided. EXAMPLES:: From e8df73013cdd36bdc944d7061c9b2ca06c0e350f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe <mkoeppe@math.ucdavis.edu> Date: Sun, 23 Apr 2023 19:14:53 -0700 Subject: [PATCH 6/8] More # optional --- src/sage/rings/big_oh.py | 23 +- .../rings/laurent_series_ring_element.pyx | 4 +- src/sage/rings/lazy_series.py | 301 ++++++++++-------- .../rings/multi_power_series_ring_element.py | 34 +- .../rings/polynomial/laurent_polynomial.pyx | 58 ++-- .../polynomial/laurent_polynomial_ring.py | 201 ++++++------ src/sage/rings/power_series_ring_element.pyx | 6 +- 7 files changed, 327 insertions(+), 300 deletions(-) diff --git a/src/sage/rings/big_oh.py b/src/sage/rings/big_oh.py index 19d02f94459..386474cf653 100644 --- a/src/sage/rings/big_oh.py +++ b/src/sage/rings/big_oh.py @@ -57,41 +57,42 @@ def O(*x, **kwds): This is also useful to create `p`-adic numbers:: - sage: O(7^6) + sage: O(7^6) # optional - sage.rings.padics O(7^6) - sage: 1/3 + O(7^6) + sage: 1/3 + O(7^6) # optional - sage.rings.padics 5 + 4*7 + 4*7^2 + 4*7^3 + 4*7^4 + 4*7^5 + O(7^6) It behaves well with respect to adding negative powers of `p`:: - sage: a = O(11^-32); a + sage: a = O(11^-32); a # optional - sage.rings.padics O(11^-32) - sage: a.parent() + sage: a.parent() # optional - sage.rings.padics 11-adic Field with capped relative precision 20 There are problems if you add a rational with very negative valuation to an `O`-Term:: - sage: 11^-12 + O(11^15) + sage: 11^-12 + O(11^15) # optional - sage.rings.padics 11^-12 + O(11^8) The reason that this fails is that the constructor doesn't know the right precision cap to use. If you cast explicitly or use other means of element creation, you can get around this issue:: - sage: K = Qp(11, 30) - sage: K(11^-12) + O(11^15) + sage: K = Qp(11, 30) # optional - sage.rings.padics + sage: K(11^-12) + O(11^15) # optional - sage.rings.padics 11^-12 + O(11^15) - sage: 11^-12 + K(O(11^15)) + sage: 11^-12 + K(O(11^15)) # optional - sage.rings.padics 11^-12 + O(11^15) - sage: K(11^-12, absprec = 15) + sage: K(11^-12, absprec=15) # optional - sage.rings.padics 11^-12 + O(11^15) - sage: K(11^-12, 15) + sage: K(11^-12, 15) # optional - sage.rings.padics 11^-12 + O(11^15) We can also work with `asymptotic expansions`_:: - sage: A.<n> = AsymptoticRing(growth_group='QQ^n * n^QQ * log(n)^QQ', coefficient_ring=QQ); A + sage: A.<n> = AsymptoticRing(growth_group='QQ^n * n^QQ * log(n)^QQ', # optional - sage.symbolic + ....: coefficient_ring=QQ); A Asymptotic Ring <QQ^n * n^QQ * log(n)^QQ * Signs^n> over Rational Field sage: O(n) O(n) diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index b11989eafbe..a854bf3076a 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -1589,8 +1589,8 @@ cdef class LaurentSeries(AlgebraElement): TESTS:: - sage: y = var('y') - sage: f.derivative(y) + sage: y = var('y') # optional - sage.symbolic + sage: f.derivative(y) # optional - sage.symbolic Traceback (most recent call last): ... ValueError: cannot differentiate with respect to y diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 581ceaac1ea..fdb2a3c0333 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -83,9 +83,9 @@ A similar statement is true for lazy symmetric functions:: - sage: h = SymmetricFunctions(QQ).h() - sage: L = LazySymmetricFunctions(h) - sage: 1 / (1-L(h[1])) + sage: h = SymmetricFunctions(QQ).h() # optional - sage.combinat + sage: L = LazySymmetricFunctions(h) # optional - sage.combinat + sage: 1 / (1-L(h[1])) # optional - sage.combinat h[] + h[1] + (h[1,1]) + (h[1,1,1]) + (h[1,1,1,1]) + (h[1,1,1,1,1]) + (h[1,1,1,1,1,1]) + O^7 We can change the base ring:: @@ -145,9 +145,9 @@ sage: check(L, z) sage: L.<z> = LazyPowerSeriesRing(QQ) sage: check(L, z) - sage: p = SymmetricFunctions(QQ).p() - sage: L = LazySymmetricFunctions(p) - sage: check(L, L(p[1])) + sage: p = SymmetricFunctions(QQ).p() # optional - sage.combinat + sage: L = LazySymmetricFunctions(p) # optional - sage.combinat + sage: check(L, L(p[1])) # optional - sage.combinat We check that the elements in the cache of the stream of homogeneous components are in the correct ring:: @@ -171,30 +171,31 @@ ....: yield n ....: n += 1 - sage: L.<z> = LazyLaurentSeriesRing(GF(2)) - sage: check(L, lambda n: n, valuation=-5) - sage: check(L, gen(), valuation=-5) + sage: L.<z> = LazyLaurentSeriesRing(GF(2)) # optional - sage.rings.finite_rings + sage: check(L, lambda n: n, valuation=-5) # optional - sage.rings.finite_rings + sage: check(L, gen(), valuation=-5) # optional - sage.rings.finite_rings sage: L = LazyDirichletSeriesRing(QQbar, "s") sage: check(L, lambda n: n, valuation=2) sage: check(L, gen(), valuation=2) - sage: L.<z> = LazyPowerSeriesRing(GF(2)) - sage: check(L, lambda n: n, valuation=0) - sage: check(L, gen(), valuation=0) + sage: L.<z> = LazyPowerSeriesRing(GF(2)) # optional - sage.rings.finite_rings + sage: check(L, lambda n: n, valuation=0) # optional - sage.rings.finite_rings + sage: check(L, gen(), valuation=0) # optional - sage.rings.finite_rings - sage: L.<x,y> = LazyPowerSeriesRing(GF(2)) - sage: check(L, lambda n: (x + y)^n, valuation=None) - sage: def gen(): + sage: L.<x,y> = LazyPowerSeriesRing(GF(2)) # optional - sage.rings.finite_rings + sage: check(L, lambda n: (x + y)^n, valuation=None) # optional - sage.rings.finite_rings + sage: def gen(): # optional - sage.rings.finite_rings ....: n = 0 ....: while True: ....: yield (x+y)^n ....: n += 1 - sage: check(L, gen(), valuation=None) + sage: check(L, gen(), valuation=None) # optional - sage.rings.finite_rings - sage: s = SymmetricFunctions(GF(2)).s() - sage: L = LazySymmetricFunctions(s) - sage: check(L, lambda n: sum(k*s(la) for k, la in enumerate(Partitions(n))), valuation=0) + sage: s = SymmetricFunctions(GF(2)).s() # optional - sage.combinat sage.rings.finite_rings + sage: L = LazySymmetricFunctions(s) # optional - sage.combinat sage.rings.finite_rings + sage: check(L, lambda n: sum(k*s(la) for k, la in enumerate(Partitions(n))), # optional - sage.combinat sage.rings.finite_rings + ....: valuation=0) """ # **************************************************************************** @@ -435,9 +436,9 @@ def coefficients(self, n=None): sage: f.coefficients() lazy list [1, 1, -1/6, ...] - sage: L.<x> = LazyPowerSeriesRing(GF(2)) - sage: f = L(lambda n: n) - sage: f.coefficients(5) + sage: L.<x> = LazyPowerSeriesRing(GF(2)) # optional - sage.rings.finite_rings + sage: f = L(lambda n: n) # optional - sage.rings.finite_rings + sage: f.coefficients(5) # optional - sage.rings.finite_rings [1, 1, 1, 1, 1] """ coeff_stream = self._coeff_stream @@ -494,9 +495,11 @@ def map_coefficients(self, f): Similarly for Dirichlet series:: sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: s = L(lambda n: n-1); s + sage: s = L(lambda n: n-1) + sage: s # optional - sage.symbolic 1/(2^z) + 2/3^z + 3/4^z + 4/5^z + 5/6^z + 6/7^z + O(1/(8^z)) - sage: s.map_coefficients(lambda c: c + 1) + sage: ms = s.map_coefficients(lambda c: c + 1) + sage: ms # optional - sage.symbolic 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + 8/8^z + O(1/(9^z)) Similarly for multivariate power series:: @@ -517,12 +520,12 @@ def map_coefficients(self, f): Similarly for lazy symmetric functions:: - sage: p = SymmetricFunctions(QQ).p() - sage: L = LazySymmetricFunctions(p) - sage: f = 1/(1-2*L(p[1])); f + sage: p = SymmetricFunctions(QQ).p() # optional - sage.combinat + sage: L = LazySymmetricFunctions(p) # optional - sage.combinat + sage: f = 1/(1-2*L(p[1])); f # optional - sage.combinat p[] + 2*p[1] + (4*p[1,1]) + (8*p[1,1,1]) + (16*p[1,1,1,1]) + (32*p[1,1,1,1,1]) + (64*p[1,1,1,1,1,1]) + O^7 - sage: f.map_coefficients(lambda c: log(c, 2)) + sage: f.map_coefficients(lambda c: log(c, 2)) # optional - sage.combinat p[1] + (2*p[1,1]) + (3*p[1,1,1]) + (4*p[1,1,1,1]) + (5*p[1,1,1,1,1]) + (6*p[1,1,1,1,1,1]) + O^7 @@ -659,9 +662,11 @@ def shift(self, n): 2 + 3*z^2 + z^5 + z^6 + z^7 + O(z^8) sage: D = LazyDirichletSeriesRing(QQ, 't') - sage: f = D([0,1,2]); f + sage: f = D([0,1,2]) + sage: f # optional - sage.symbolic 1/(2^t) + 2/3^t - sage: f.shift(3) + sage: sf = f.shift(3) + sage: sf # optional - sage.symbolic 1/(5^t) + 2/6^t Examples with power series (where the minimal valuation is `0`):: @@ -1005,60 +1010,60 @@ def __bool__(self): TESTS:: - sage: L.<z> = LazyLaurentSeriesRing(GF(2)) - sage: bool(z-z) + sage: L.<z> = LazyLaurentSeriesRing(GF(2)) # optional - sage.rings.finite_rings + sage: bool(z - z) # optional - sage.rings.finite_rings False - sage: f = 1/(1 - z) - sage: bool(f) + sage: f = 1/(1 - z) # optional - sage.rings.finite_rings + sage: bool(f) # optional - sage.rings.finite_rings True - sage: M = L(lambda n: n, valuation=0); M + sage: M = L(lambda n: n, valuation=0); M # optional - sage.rings.finite_rings z + z^3 + z^5 + O(z^7) - sage: M.is_zero() + sage: M.is_zero() # optional - sage.rings.finite_rings False - sage: M = L(lambda n: 2*n if n < 10 else 1, valuation=0); M + sage: M = L(lambda n: 2*n if n < 10 else 1, valuation=0); M # optional - sage.rings.finite_rings O(z^7) - sage: bool(M) + sage: bool(M) # optional - sage.rings.finite_rings Traceback (most recent call last): ... ValueError: undecidable as lazy Laurent series - sage: M[15] + sage: M[15] # optional - sage.rings.finite_rings 1 - sage: bool(M) + sage: bool(M) # optional - sage.rings.finite_rings True - sage: L.<z> = LazyLaurentSeriesRing(GF(2), sparse=True) - sage: M = L(lambda n: 2*n if n < 10 else 1, valuation=0); M + sage: L.<z> = LazyLaurentSeriesRing(GF(2), sparse=True) # optional - sage.rings.finite_rings + sage: M = L(lambda n: 2*n if n < 10 else 1, valuation=0); M # optional - sage.rings.finite_rings O(z^7) - sage: bool(M) + sage: bool(M) # optional - sage.rings.finite_rings Traceback (most recent call last): ... ValueError: undecidable as lazy Laurent series - sage: M[15] + sage: M[15] # optional - sage.rings.finite_rings 1 - sage: bool(M) + sage: bool(M) # optional - sage.rings.finite_rings True Uninitialized series:: - sage: g = L.undefined(valuation=0) - sage: bool(g) + sage: g = L.undefined(valuation=0) # optional - sage.rings.finite_rings + sage: bool(g) # optional - sage.rings.finite_rings True - sage: g.define(0) - sage: bool(g) + sage: g.define(0) # optional - sage.rings.finite_rings + sage: bool(g) # optional - sage.rings.finite_rings False - sage: g = L.undefined(valuation=0) - sage: bool(g) + sage: g = L.undefined(valuation=0) # optional - sage.rings.finite_rings + sage: bool(g) # optional - sage.rings.finite_rings True - sage: g.define(1 + z) - sage: bool(g) + sage: g.define(1 + z) # optional - sage.rings.finite_rings + sage: bool(g) # optional - sage.rings.finite_rings True - sage: g = L.undefined(valuation=0) - sage: bool(g) + sage: g = L.undefined(valuation=0) # optional - sage.rings.finite_rings + sage: bool(g) # optional - sage.rings.finite_rings True - sage: g.define(1 + z*g) - sage: bool(g) + sage: g.define(1 + z*g) # optional - sage.rings.finite_rings + sage: bool(g) # optional - sage.rings.finite_rings True """ if isinstance(self._coeff_stream, Stream_zero): @@ -1197,14 +1202,14 @@ def define(self, s): We can compute the Frobenius character of unlabeled trees:: - sage: m = SymmetricFunctions(QQ).m() - sage: s = SymmetricFunctions(QQ).s() - sage: L = LazySymmetricFunctions(m) - sage: E = L(lambda n: s[n], valuation=0) - sage: X = L(s[1]) - sage: A = L.undefined() - sage: A.define(X*E(A, check=False)) - sage: A[:6] + sage: m = SymmetricFunctions(QQ).m() # optional - sage.combinat + sage: s = SymmetricFunctions(QQ).s() # optional - sage.combinat + sage: L = LazySymmetricFunctions(m) # optional - sage.combinat + sage: E = L(lambda n: s[n], valuation=0) # optional - sage.combinat + sage: X = L(s[1]) # optional - sage.combinat + sage: A = L.undefined() # optional - sage.combinat + sage: A.define(X*E(A, check=False)) # optional - sage.combinat + sage: A[:6] # optional - sage.combinat [m[1], 2*m[1, 1] + m[2], 9*m[1, 1, 1] + 5*m[2, 1] + 2*m[3], @@ -1246,7 +1251,7 @@ def define(self, s): sage: g = D.undefined(valuation=2) sage: o = D(constant=1, valuation=2) sage: g.define(o * e(g)) - sage: g + sage: g # optional - sage.symbolic 1/(2^s) + 1/(3^s) + 2/4^s + 1/(5^s) + 3/6^s + 1/(7^s) + 9/2/8^s + O(1/(9^s)) For Laurent series there is no minimal valuation, so it has @@ -1271,7 +1276,7 @@ def define(self, s): sage: g = D([0, 1]) sage: f = D.undefined() sage: f.define(1 + ~f*g) - sage: f + sage: f # optional - sage.symbolic 1 + 1/(2^s) - 1/(4^s) + O(1/(8^s)) sage: oeis(f[:30]) # optional, internet @@ -1319,11 +1324,11 @@ def define(self, s): sage: f 1 + 2*t + 12*t^3 + 32*t^4 + 368*t^5 + 2192*t^6 + O(t^7) - sage: s = SymmetricFunctions(QQ).s() - sage: L = LazySymmetricFunctions(s) - sage: f = L.undefined() - sage: f.define(1+(s[1]*f).revert()) - sage: f + sage: s = SymmetricFunctions(QQ).s() # optional - sage.combinat + sage: L = LazySymmetricFunctions(s) # optional - sage.combinat + sage: f = L.undefined() # optional - sage.combinat + sage: f.define(1+(s[1]*f).revert()) # optional - sage.combinat + sage: f # optional - sage.combinat s[] + s[1] + (-s[1,1]-s[2]) + (3*s[1,1,1]+6*s[2,1]+3*s[3]) + (-13*s[1,1,1,1]-39*s[2,1,1]-26*s[2,2]-39*s[3,1]-13*s[4]) @@ -1331,7 +1336,7 @@ def define(self, s): + (-419*s[1,1,1,1,1,1]-2095*s[2,1,1,1,1]-3771*s[2,2,1,1]-2095*s[2,2,2]-4190*s[3,1,1,1]-6704*s[3,2,1]-2095*s[3,3]-4190*s[4,1,1]-3771*s[4,2]-2095*s[5,1]-419*s[6]) + O^7 - sage: (f*s[1]).revert() + 1 - f + sage: (f*s[1]).revert() + 1 - f # optional - sage.combinat O^7 """ @@ -1454,12 +1459,12 @@ def _ascii_art_(self): EXAMPLES:: - sage: e = SymmetricFunctions(QQ).e() - sage: L.<z> = LazyLaurentSeriesRing(e) - sage: L.options.display_length = 3 - sage: ascii_art(1 / (1 - e[1]*z)) + sage: e = SymmetricFunctions(QQ).e() # optional - sage.combinat + sage: L.<z> = LazyLaurentSeriesRing(e) # optional - sage.combinat + sage: L.options.display_length = 3 # optional - sage.combinat + sage: ascii_art(1 / (1 - e[1]*z)) # optional - sage.combinat e[] + e[1]*z + e[1, 1]*z^2 + O(e[]*z^3) - sage: L.options._reset() + sage: L.options._reset() # optional - sage.combinat """ from sage.typeset.ascii_art import ascii_art, AsciiArt if isinstance(self._coeff_stream, Stream_zero): @@ -1474,12 +1479,12 @@ def _unicode_art_(self): EXAMPLES:: - sage: e = SymmetricFunctions(QQ).e() - sage: L.<z> = LazyLaurentSeriesRing(e) - sage: L.options.display_length = 3 - sage: unicode_art(1 / (1 - e[1]*z)) + sage: e = SymmetricFunctions(QQ).e() # optional - sage.combinat + sage: L.<z> = LazyLaurentSeriesRing(e) # optional - sage.combinat + sage: L.options.display_length = 3 # optional - sage.combinat + sage: unicode_art(1 / (1 - e[1]*z)) # optional - sage.combinat e[] + e[1]*z + e[1, 1]*z^2 + O(e[]*z^3) - sage: L.options._reset() + sage: L.options._reset() # optional - sage.combinat """ from sage.typeset.unicode_art import unicode_art, UnicodeArt if isinstance(self._coeff_stream, Stream_zero): @@ -1533,7 +1538,8 @@ def change_ring(self, ring): sage: t = s.change_ring(QQ) sage: t.parent() Lazy Dirichlet Series Ring in z over Rational Field - sage: t^-1 + sage: it = t^-1 + sage: it # optional - sage.symbolic 1/2 - 1/2/2^z - 1/2/3^z - 1/2/5^z + 1/2/6^z - 1/2/7^z + O(1/(8^z)) A Taylor series example:: @@ -1600,23 +1606,29 @@ def _add_(self, other): Similarly for Dirichlet series:: sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: s = L(lambda n: n); s + sage: s = L(lambda n: n) + sage: s # optional - sage.symbolic 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) - sage: t = L(constant=1); t + sage: t = L(constant=1) + sage: t # optional - sage.symbolic 1 + 1/(2^z) + 1/(3^z) + O(1/(4^z)) - sage: s + t + sage: st = s + t + sage: st # optional - sage.symbolic 2 + 3/2^z + 4/3^z + 5/4^z + 6/5^z + 7/6^z + 8/7^z + O(1/(8^z)) sage: r = L(constant=-1) - sage: r + t + sage: rt = r + t + sage: rt # optional - sage.symbolic 0 sage: r = L([1,2,3]) - sage: r + t + sage: rt = r + t + sage: rt # optional - sage.symbolic 2 + 3/2^z + 4/3^z + 1/(4^z) + 1/(5^z) + 1/(6^z) + O(1/(7^z)) sage: r = L([1,2,3], constant=-1) - sage: r + t + sage: rt = r + t + sage: rt # optional - sage.symbolic 2 + 3/2^z + 4/3^z """ P = self.parent() @@ -1811,15 +1823,16 @@ def _acted_upon_(self, scalar, self_on_left): sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: g = L([0,1]) - sage: 2 * g + sage: 2 * g # optional - sage.symbolic 2/2^z - sage: -1 * g + sage: -1 * g # optional - sage.symbolic -1/(2^z) - sage: 0*g + sage: 0*g # optional - sage.symbolic 0 - sage: M = L(lambda n: n); M + sage: M = L(lambda n: n) + sage: M # optional - sage.symbolic 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) - sage: 3 * M + sage: 3 * M # optional - sage.symbolic 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + O(1/(8^z)) sage: 1 * M is M @@ -1942,7 +1955,7 @@ def exp(self): sage: L = LazyDirichletSeriesRing(QQ, "s") sage: Z = L(constant=1, valuation=2) - sage: exp(Z) + sage: exp(Z) # optional - sage.symbolic 1 + 1/(2^s) + 1/(3^s) + 3/2/4^s + 1/(5^s) + 2/6^s + 1/(7^s) + O(1/(8^s)) """ from .lazy_series_ring import LazyLaurentSeriesRing @@ -1958,7 +1971,7 @@ def log(self): sage: L = LazyDirichletSeriesRing(QQ, "s") sage: Z = L(constant=1) - sage: log(Z) + sage: log(Z) # optional - sage.symbolic 1/(2^s) + 1/(3^s) + 1/2/4^s + 1/(5^s) + 1/(7^s) + O(1/(8^s)) """ from .lazy_series_ring import LazyLaurentSeriesRing @@ -2611,14 +2624,14 @@ def __pow__(self, n): sage: D = LazyDirichletSeriesRing(QQ, 's') sage: Z = D(constant=1) - sage: Z^2 + sage: Z^2 # optional - sage.symbolic 1 + 2/2^s + 2/3^s + 3/4^s + 2/5^s + 4/6^s + 2/7^s + O(1/(8^s)) sage: f = Z^(1/3) - sage: f + sage: f # optional - sage.symbolic 1 + 1/3/2^s + 1/3/3^s + 2/9/4^s + 1/3/5^s + 1/9/6^s + 1/3/7^s + O(1/(8^s)) - sage: f^2 + sage: f^2 # optional - sage.symbolic 1 + 2/3/2^s + 2/3/3^s + 5/9/4^s + 2/3/5^s + 4/9/6^s + 2/3/7^s + O(1/(8^s)) - sage: f^3 - Z + sage: f^3 - Z # optional - sage.symbolic O(1/(8^s)) sage: L.<z> = LazyLaurentSeriesRing(QQ) @@ -2675,9 +2688,9 @@ def sqrt(self): sage: D = LazyDirichletSeriesRing(SR, "s") sage: Z = D(constant=1) sage: f = sqrt(Z) - sage: f + sage: f # optional - sage.symbolic 1 + 1/2/2^s + 1/2/3^s + 3/8/4^s + 1/2/5^s + 1/4/6^s + 1/2/7^s + O(1/(8^s)) - sage: f*f - Z + sage: f*f - Z # optional - sage.symbolic O(1/(8^s)) """ return self ** QQ((1, 2)) # == 1/2 @@ -3489,17 +3502,16 @@ def _im_gens_(self, codomain, im_gens, base_map=None): EXAMPLES:: sage: Z.<x> = ZZ[] - sage: K.<i> = NumberField(x^2 + 1) - sage: R.<t> = LazyLaurentSeriesRing(K) - sage: f = R(lambda n: i^n, valuation=-2) - sage: f + sage: K.<i> = NumberField(x^2 + 1) # optional - sage.rings.number_field + sage: R.<t> = LazyLaurentSeriesRing(K) # optional - sage.rings.number_field + sage: f = R(lambda n: i^n, valuation=-2); f # optional - sage.rings.number_field -t^-2 - i*t^-1 + 1 + i*t - t^2 - i*t^3 + t^4 + O(t^5) - sage: f._im_gens_(R, [t + t^2]) + sage: f._im_gens_(R, [t + t^2]) # optional - sage.rings.number_field -t^-2 + (-i + 2)*t^-1 + (i - 2) + 4*t + (2*i - 6)*t^2 + (-2*i + 4)*t^3 + (-2*i - 7)*t^4 + O(t^5) - sage: cc = K.hom([-i]) - sage: f._im_gens_(R, [t + t^2], base_map=cc) + sage: cc = K.hom([-i]) # optional - sage.rings.number_field + sage: f._im_gens_(R, [t + t^2], base_map=cc) # optional - sage.rings.number_field -t^-2 + (i + 2)*t^-1 + (-i - 2) + 4*t + (-2*i - 6)*t^2 + (2*i + 4)*t^3 + (2*i - 7)*t^4 + O(t^5) """ @@ -3735,7 +3747,8 @@ def __call__(self, g, *, check=True): sage: L.<z> = LazyLaurentSeriesRing(QQ) sage: e = L(lambda n: 1/factorial(n), 0) sage: D = LazyDirichletSeriesRing(QQ, "s") - sage: g = D(constant=1)-1; g + sage: g = D(constant=1)-1 + sage: g # optional - sage.symbolic 1/(2^s) + 1/(3^s) + 1/(4^s) + O(1/(5^s)) sage: e(g)[0:10] @@ -3744,7 +3757,8 @@ def __call__(self, g, *, check=True): sage: sum(g^k/factorial(k) for k in range(10))[0:10] [0, 1, 1, 1, 3/2, 1, 2, 1, 13/6, 3/2] - sage: g = D([0,1,0,1,1,2]); g + sage: g = D([0,1,0,1,1,2]) + sage: g # optional - sage.symbolic 1/(2^s) + 1/(4^s) + 1/(5^s) + 2/6^s sage: e(g)[0:10] [0, 1, 1, 0, 3/2, 1, 2, 0, 7/6, 0] @@ -3756,11 +3770,12 @@ def __call__(self, g, *, check=True): ... ValueError: can only compose with a positive valuation series - sage: e5 = L(e, degree=5); e5 + sage: e5 = L(e, degree=5) + sage: e5 # optional - sage.symbolic 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 - sage: e5(g) + sage: e5(g) # optional - sage.symbolic 1 + 1/(2^s) + 3/2/4^s + 1/(5^s) + 2/6^s + O(1/(8^s)) - sage: sum(e5[k] * g^k for k in range(5)) + sage: sum(e5[k] * g^k for k in range(5)) # optional - sage.symbolic 1 + 1/(2^s) + 3/2/4^s + 1/(5^s) + 2/6^s + O(1/(8^s)) The output parent is always the common parent between the base ring @@ -4531,24 +4546,27 @@ def __call__(self, *g, check=True): We perform the composition with a lazy Dirichlet series:: sage: D = LazyDirichletSeriesRing(QQ, "s") - sage: g = D(constant=1)-1; g + sage: g = D(constant=1)-1 + sage: g # optional - sage.symbolic 1/(2^s) + 1/(3^s) + 1/(4^s) + O(1/(5^s)) sage: f = 1 / (1 - x - y*z); f 1 + x + (x^2+y*z) + (x^3+2*x*y*z) + (x^4+3*x^2*y*z+y^2*z^2) + (x^5+4*x^3*y*z+3*x*y^2*z^2) + (x^6+5*x^4*y*z+6*x^2*y^2*z^2+y^3*z^3) + O(x,y,z)^7 - sage: fog = f(g, g, g); fog + sage: fog = f(g, g, g) + sage: fog # optional - sage.symbolic 1 + 1/(2^s) + 1/(3^s) + 3/4^s + 1/(5^s) + 5/6^s + O(1/(7^s)) - sage: fg = 1 / (1 - g - g*g); fg + sage: fg = 1 / (1 - g - g*g) + sage: fg # optional - sage.symbolic 1 + 1/(2^s) + 1/(3^s) + 3/4^s + 1/(5^s) + 5/6^s + 1/(7^s) + O(1/(8^s)) - sage: fog - fg + sage: fog - fg # optional - sage.symbolic O(1/(8^s)) sage: f = 1 / (1 - 2*a) - sage: f(g) + sage: f(g) # optional - sage.symbolic 1 + 2/2^s + 2/3^s + 6/4^s + 2/5^s + 10/6^s + 2/7^s + O(1/(8^s)) - sage: 1 / (1 - 2*g) + sage: 1 / (1 - 2*g) # optional - sage.symbolic 1 + 2/2^s + 2/3^s + 6/4^s + 2/5^s + 10/6^s + 2/7^s + O(1/(8^s)) The output parent is always the common parent between the base ring @@ -6318,7 +6336,8 @@ class LazyDirichletSeries(LazyModuleElement): EXAMPLES:: sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: f = L(constant=1)^2; f + sage: f = L(constant=1)^2 + sage: f # optional - sage.symbolic 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + O(1/(8^z)) sage: f.coefficient(100) == number_of_divisors(100) True @@ -6326,7 +6345,7 @@ class LazyDirichletSeries(LazyModuleElement): Lazy Dirichlet series is picklable:: sage: g = loads(dumps(f)) - sage: g + sage: g # optional - sage.symbolic 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + O(1/(8^z)) sage: g == f True @@ -6392,35 +6411,37 @@ def _mul_(self, other): TESTS:: sage: D = LazyDirichletSeriesRing(QQ, "s") - sage: zeta = D(constant=1); zeta + sage: zeta = D(constant=1) + sage: zeta # optional - sage.symbolic 1 + 1/(2^s) + 1/(3^s) + O(1/(4^s)) - sage: zeta * zeta + sage: zeta * zeta # optional - sage.symbolic 1 + 2/2^s + 2/3^s + 3/4^s + 2/5^s + 4/6^s + 2/7^s + O(1/(8^s)) sage: [number_of_divisors(n) for n in range(1, 8)] [1, 2, 2, 3, 2, 4, 2] - sage: mu = D(moebius); mu + sage: mu = D(moebius) + sage: mu # optional - sage.symbolic 1 - 1/(2^s) - 1/(3^s) - 1/(5^s) + 1/(6^s) - 1/(7^s) + O(1/(8^s)) - sage: zeta * mu + sage: zeta * mu # optional - sage.symbolic 1 + O(1/(8^s)) sage: D.one() * mu is mu True sage: mu * D.one() is mu True - sage: zeta*(2-zeta) + sage: zeta*(2-zeta) # optional - sage.symbolic 1 - 1/(4^s) - 2/6^s + O(1/(8^s)) sage: d1 = D([0,0,1,2,3]) sage: d2 = D([0,1,2,3]) - sage: d1 * d2 + sage: d1 * d2 # optional - sage.symbolic 1/(6^s) + 2/8^s + 2/9^s + 3/10^s + 7/12^s + O(1/(13^s)) - sage: d1 * d2 # not tested - exact result + sage: d1 * d2 # not tested - exact result # optional - sage.symbolic 1/(6^s) + 2/8^s + 2/9^s + 3/10^s + 7/12^s + 6/15^s + 6/16^s + 9/20^s sage: L.<t> = LazyLaurentSeriesRing(D) - sage: 1/(1-t*zeta) + sage: 1/(1-t*zeta) # optional - sage.symbolic (1 + O(1/(8^s))) + (1 + 1/(2^s) + 1/(3^s) + 1/(4^s) + 1/(5^s) + 1/(6^s) + 1/(7^s) + O(1/(8^s)))*t + (1 + 2/2^s + 2/3^s + 3/4^s + 2/5^s + 4/6^s + 2/7^s + O(1/(8^s)))*t^2 @@ -6533,7 +6554,8 @@ def __call__(self, p, *, check=True): sage: Z(1) Infinity - sage: f = D([1,2,-3,-4], valuation=2); f + sage: f = D([1,2,-3,-4], valuation=2) + sage: f # optional - sage.symbolic 1/(2^s) + 2/3^s - 3/4^s - 4/5^s sage: f(2) 449/3600 @@ -6603,22 +6625,22 @@ def _format_series(self, formatter, format_strings=False): sage: L = LazyDirichletSeriesRing(QQ, "s") sage: f = L(constant=1) - sage: f._format_series(repr) + sage: f._format_series(repr) # optional - sage.symbolic '1 + 1/(2^s) + 1/(3^s) + O(1/(4^s))' - sage: f._format_series(unicode_art) + sage: f._format_series(unicode_art) # optional - sage.symbolic -s -s 1 + 2 + 3 + O(1/(4^s)) - sage: L([1,-1,1])._format_series(repr) + sage: L([1,-1,1])._format_series(repr) # optional - sage.symbolic '1 - 1/(2^s) + 1/(3^s)' - sage: L([1,-1,1])._format_series(ascii_art) + sage: L([1,-1,1])._format_series(ascii_art) # optional - sage.symbolic -s -s 1 + -2 + 3 sage: R.<x> = QQ[] sage: L = LazyDirichletSeriesRing(R, "s") - sage: L([1,-1 + x,1/3])._format_series(ascii_art) + sage: L([1,-1 + x,1/3])._format_series(ascii_art) # optional - sage.symbolic ( -s) (3 ) ( -s ) (---) @@ -6626,9 +6648,10 @@ def _format_series(self, formatter, format_strings=False): sage: L.<z> = LazyLaurentSeriesRing(QQ) sage: D = LazyDirichletSeriesRing(L, "s") - sage: f = D([2, 0, 1/(1-z), 3]); f + sage: f = D([2, 0, 1/(1-z), 3]) + sage: f # optional - sage.symbolic (2)/1^s + ((1+z+z^2+O(z^3))/3^s) + (3)/4^s - sage: f._format_series(ascii_art) + sage: f._format_series(ascii_art) # optional - sage.symbolic ((2)/1^s) + ((1 + z + z^2 + O(z^3))/3^s) + ((3)/4^s) """ P = self.parent() diff --git a/src/sage/rings/multi_power_series_ring_element.py b/src/sage/rings/multi_power_series_ring_element.py index 978de36ce2d..b3e902b9735 100644 --- a/src/sage/rings/multi_power_series_ring_element.py +++ b/src/sage/rings/multi_power_series_ring_element.py @@ -892,14 +892,14 @@ def quo_rem(self, other, precision=None): sage: R.<a,b,c> = PowerSeriesRing(ZZ) sage: f = 1 + a + b - a*b + R.O(3) sage: g = 1 + 2*a - 3*a*b + R.O(3) - sage: q, r = f.quo_rem(g); q, r + sage: q, r = f.quo_rem(g); q, r # optional - sage.libs.singular (1 - a + b + 2*a^2 + O(a, b, c)^3, 0 + O(a, b, c)^3) - sage: f == q*g+r + sage: f == q*g + r # optional - sage.libs.singular True - sage: q, r = (a*f).quo_rem(g); q, r + sage: q, r = (a*f).quo_rem(g); q, r # optional - sage.libs.singular (a - a^2 + a*b + 2*a^3 + O(a, b, c)^4, 0 + O(a, b, c)^4) - sage: a*f == q*g+r + sage: a*f == q*g + r # optional - sage.libs.singular True sage: q, r = (a*f).quo_rem(a*g); q, r @@ -1897,9 +1897,9 @@ def exp(self, prec=infinity): sage: f = a + b + a*b + T.O(3) sage: exp(f) 1 + a + b + 1/2*a^2 + 2*a*b + 1/2*b^2 + O(a, b)^3 - sage: f.exp() + sage: f.exp() # optional - sage.symbolic 1 + a + b + 1/2*a^2 + 2*a*b + 1/2*b^2 + O(a, b)^3 - sage: f.exp(prec=2) + sage: f.exp(prec=2) # optional - sage.symbolic 1 + a + b + O(a, b)^2 sage: log(exp(f)) - f 0 + O(a, b)^3 @@ -1987,11 +1987,11 @@ def log(self, prec=infinity): sage: T.<a,b> = PowerSeriesRing(ZZ,2) sage: f = 1 + a + b + a*b + T.O(5) - sage: f.log() + sage: f.log() # optional - sage.symbolic a + b - 1/2*a^2 - 1/2*b^2 + 1/3*a^3 + 1/3*b^3 - 1/4*a^4 - 1/4*b^4 + O(a, b)^5 - sage: log(f) + sage: log(f) # optional - sage.symbolic a + b - 1/2*a^2 - 1/2*b^2 + 1/3*a^3 + 1/3*b^3 - 1/4*a^4 - 1/4*b^4 + O(a, b)^5 - sage: exp(log(f)) - f + sage: exp(log(f)) - f # optional - sage.symbolic 0 + O(a, b)^5 If the power series has a constant coefficient `c` and @@ -1999,8 +1999,8 @@ def log(self, prec=infinity): power series over the :class:`~sage.symbolic.ring.SymbolicRing`. These are not yet implemented and therefore such cases raise an error:: - sage: g = 2+f - sage: log(g) + sage: g = 2 + f # optional - sage.symbolic + sage: log(g) # optional - sage.symbolic Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for -: 'Symbolic Ring' and 'Power @@ -2009,7 +2009,7 @@ def log(self, prec=infinity): Another workaround for this limitation is to change base ring to one which is closed under exponentiation, such as `\RR` or `\CC`:: - sage: log(g.change_ring(RDF)) + sage: log(g.change_ring(RDF)) # optional - sage.symbolic 1.09861228... + 0.333333333...*a + 0.333333333...*b - 0.0555555555...*a^2 + 0.222222222...*a*b - 0.0555555555...*b^2 + 0.0123456790...*a^3 - 0.0740740740...*a^2*b - 0.0740740740...*a*b^2 + 0.0123456790...*b^3 @@ -2018,17 +2018,17 @@ def log(self, prec=infinity): TESTS:: - sage: (1+a).log(prec=10).exp() + sage: (1+a).log(prec=10).exp() # optional - sage.symbolic 1 + a + O(a, b)^10 - sage: a.exp(prec=10).log() + sage: a.exp(prec=10).log() # optional - sage.symbolic a + O(a, b)^10 - sage: log(1+a) + sage: log(1+a) # optional - sage.symbolic a - 1/2*a^2 + 1/3*a^3 - 1/4*a^4 + 1/5*a^5 - 1/6*a^6 + 1/7*a^7 - 1/8*a^8 + 1/9*a^9 - 1/10*a^10 + 1/11*a^11 + O(a, b)^12 - sage: -log(1-a+T.O(5)) + sage: -log(1-a+T.O(5)) # optional - sage.symbolic a + 1/2*a^2 + 1/3*a^3 + 1/4*a^4 + O(a, b)^5 - sage: a.log(prec=10) + sage: a.log(prec=10) # optional - sage.symbolic Traceback (most recent call last): ... ValueError: Can only take formal power series for non-zero constant term. diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 0604b0f0111..e7b17b2cd32 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -30,8 +30,8 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): EXAMPLES:: - sage: L.<x,y> = LaurentPolynomialRing(QQ) # indirect doctest - sage: x*y + sage: L.<x,y> = LaurentPolynomialRing(QQ) # indirect doctest # optional - sage.modules + sage: x*y # optional - sage.modules x*y """ cdef type t = type(self) @@ -113,18 +113,18 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): :: - sage: L.<a, b> = LaurentPolynomialRing(QQ) - sage: L(42)._integer_(ZZ) + sage: L.<a, b> = LaurentPolynomialRing(QQ) # optional - sage.modules + sage: L(42)._integer_(ZZ) # optional - sage.modules 42 - sage: a._integer_(ZZ) + sage: a._integer_(ZZ) # optional - sage.modules Traceback (most recent call last): ... ValueError: a is not constant - sage: L(2/3)._integer_(ZZ) + sage: L(2/3)._integer_(ZZ) # optional - sage.modules Traceback (most recent call last): ... TypeError: no conversion of this rational to integer - sage: ZZ(L(42)) + sage: ZZ(L(42)) # optional - sage.modules 42 """ if not self.is_constant(): @@ -155,14 +155,14 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): :: - sage: L.<a, b> = LaurentPolynomialRing(QQ) - sage: L(42)._rational_() + sage: L.<a, b> = LaurentPolynomialRing(QQ) # optional - sage.modules + sage: L(42)._rational_() # optional - sage.modules 42 - sage: a._rational_() + sage: a._rational_() # optional - sage.modules Traceback (most recent call last): ... ValueError: a is not constant - sage: QQ(L(2/3)) + sage: QQ(L(2/3)) # optional - sage.modules 2/3 """ if not self.is_constant(): @@ -272,22 +272,22 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): From: Finite Field in r of size 3^2 To: Finite Field in s of size 3^4 Defn: r |--> 2*s^3 + 2*s^2 + 1 - sage: T.<X,Y> = LaurentPolynomialRing(R, 2) # optional - sage.rings.finite_rings - sage: f = r*X + Y # optional - sage.rings.finite_rings - sage: g = f.map_coefficients(h); g # optional - sage.rings.finite_rings + sage: T.<X,Y> = LaurentPolynomialRing(R, 2) # optional - sage.modules sage.rings.finite_rings + sage: f = r*X + Y # optional - sage.modules sage.rings.finite_rings + sage: g = f.map_coefficients(h); g # optional - sage.modules sage.rings.finite_rings (2*s^3 + 2*s^2 + 1)*X + Y - sage: g.parent() # optional - sage.rings.finite_rings + sage: g.parent() # optional - sage.modules sage.rings.finite_rings Multivariate Laurent Polynomial Ring in X, Y over Finite Field in s of size 3^4 - sage: h = lambda x: x.trace() # optional - sage.rings.finite_rings - sage: g = f.map_coefficients(h); g # optional - sage.rings.finite_rings + sage: h = lambda x: x.trace() + sage: g = f.map_coefficients(h); g # optional - sage.modules sage.rings.finite_rings X - Y - sage: g.parent() # optional - sage.rings.finite_rings + sage: g.parent() # optional - sage.modules sage.rings.finite_rings Multivariate Laurent Polynomial Ring in X, Y over Finite Field in r of size 3^2 - sage: g = f.map_coefficients(h, new_base_ring=GF(3)); g # optional - sage.rings.finite_rings + sage: g = f.map_coefficients(h, new_base_ring=GF(3)); g # optional - sage.modules sage.rings.finite_rings X - Y - sage: g.parent() # optional - sage.rings.finite_rings + sage: g.parent() # optional - sage.modules sage.rings.finite_rings Multivariate Laurent Polynomial Ring in X, Y over Finite Field of size 3 """ @@ -442,7 +442,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): EXAMPLES:: sage: R.<t> = LaurentPolynomialRing(QQ) - sage: (2+t).is_unit() + sage: (2 + t).is_unit() False sage: f = 2*t sage: f.is_unit() @@ -537,7 +537,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): EXAMPLES:: sage: R.<t> = LaurentPolynomialRing(QQ) - sage: elt = t^2 + t^4 # indirect doctest + sage: elt = t^2 + t^4 # indirect doctest sage: elt.polynomial_construction() (t^2 + 1, 2) @@ -1628,10 +1628,10 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): The answer is dependent of the base ring:: - sage: S.<u> = LaurentPolynomialRing(QQbar) - sage: (2 + 4*t + 2*t^2).is_square() + sage: S.<u> = LaurentPolynomialRing(QQbar) # optional - sage.rings.number_field + sage: (2 + 4*t + 2*t^2).is_square() # optional - sage.rings.number_field False - sage: (2 + 4*u + 2*u^2).is_square() + sage: (2 + 4*u + 2*u^2).is_square() # optional - sage.rings.number_field True TESTS:: @@ -1756,10 +1756,10 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: R.<x> = LaurentPolynomialRing(ZZ) sage: p = 1/x + 1 + x - sage: x,y = var("x, y") - sage: p._derivative(x) + sage: x,y = var("x, y") # optional - sage.symbolic + sage: p._derivative(x) # optional - sage.symbolic -x^-2 + 1 - sage: p._derivative(y) + sage: p._derivative(y) # optional - sage.symbolic Traceback (most recent call last): ... ValueError: cannot differentiate with respect to y @@ -1906,7 +1906,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: R.<t> = LaurentPolynomialRing(ZZ) sage: f = 4*t^-7 + 3*t^3 + 2*t^4 + t^-6 - sage: f.factor() + sage: f.factor() # optional - sage.libs.pari (t^-7) * (4 + t + 3*t^10 + 2*t^11) """ cdef LaurentPolynomial_univariate u, d diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index e3fb6e0992d..5ed4a096438 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -20,7 +20,7 @@ sage: A.<Y> = QQ[] sage: R.<X> = LaurentPolynomialRing(A) - sage: matrix(R,2,2,[X,0,0,1]) + sage: matrix(R,2,2,[X,0,0,1]) # optional - sage.modules [X 0] [0 1] @@ -64,8 +64,8 @@ def is_LaurentPolynomialRing(R): See https://github.com/sagemath/sage/issues/35229 for details. False - sage: R = LaurentPolynomialRing(QQ,3,'x') - sage: is_LaurentPolynomialRing(R) + sage: R = LaurentPolynomialRing(QQ,3,'x') # optional - sage.modules + sage: is_LaurentPolynomialRing(R) # optional - sage.modules True """ from sage.misc.superseded import deprecation @@ -121,9 +121,9 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): :: - sage: R.<x,y> = LaurentPolynomialRing(QQ,2); R + sage: R.<x,y> = LaurentPolynomialRing(QQ, 2); R # optional - sage.modules Multivariate Laurent Polynomial Ring in x, y over Rational Field - sage: f = x^2 - 2*y^-2 + sage: f = x^2 - 2*y^-2 # optional - sage.modules You can't just globally change the names of those variables. This is because objects all over Sage could have pointers to @@ -131,7 +131,7 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): :: - sage: R._assign_names(['z','w']) + sage: R._assign_names(['z','w']) # optional - sage.modules Traceback (most recent call last): ... ValueError: variable names cannot be changed after object creation. @@ -175,31 +175,31 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): :: - sage: R = LaurentPolynomialRing(QQ, 'a,b,c'); R + sage: R = LaurentPolynomialRing(QQ, 'a,b,c'); R # optional - sage.modules Multivariate Laurent Polynomial Ring in a, b, c over Rational Field - sage: S = LaurentPolynomialRing(QQ, ['a','b','c']); S + sage: S = LaurentPolynomialRing(QQ, ['a','b','c']); S # optional - sage.modules Multivariate Laurent Polynomial Ring in a, b, c over Rational Field - sage: T = LaurentPolynomialRing(QQ, ('a','b','c')); T + sage: T = LaurentPolynomialRing(QQ, ('a','b','c')); T # optional - sage.modules Multivariate Laurent Polynomial Ring in a, b, c over Rational Field All three rings are identical. :: - sage: (R is S) and (S is T) + sage: (R is S) and (S is T) # optional - sage.modules True There is a unique Laurent polynomial ring with each term order:: - sage: R = LaurentPolynomialRing(QQ, 'x,y,z', order='degrevlex'); R + sage: R = LaurentPolynomialRing(QQ, 'x,y,z', order='degrevlex'); R # optional - sage.modules Multivariate Laurent Polynomial Ring in x, y, z over Rational Field - sage: S = LaurentPolynomialRing(QQ, 'x,y,z', order='invlex'); S + sage: S = LaurentPolynomialRing(QQ, 'x,y,z', order='invlex'); S # optional - sage.modules Multivariate Laurent Polynomial Ring in x, y, z over Rational Field - sage: S is LaurentPolynomialRing(QQ, 'x,y,z', order='invlex') + sage: S is LaurentPolynomialRing(QQ, 'x,y,z', order='invlex') # optional - sage.modules True - sage: R == S + sage: R == S # optional - sage.modules False @@ -210,24 +210,27 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): :: - sage: LaurentPolynomialRing(QQ, 'x', 10) - Multivariate Laurent Polynomial Ring in x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 over Rational Field + sage: LaurentPolynomialRing(QQ, 'x', 10) # optional - sage.modules + Multivariate Laurent Polynomial Ring in x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 + over Rational Field - sage: LaurentPolynomialRing(GF(7), 'y', 5) - Multivariate Laurent Polynomial Ring in y0, y1, y2, y3, y4 over Finite Field of size 7 + sage: LaurentPolynomialRing(GF(7), 'y', 5) # optional - sage.modules sage.rings.finite_rings + Multivariate Laurent Polynomial Ring in y0, y1, y2, y3, y4 + over Finite Field of size 7 - sage: LaurentPolynomialRing(QQ, 'y', 3, sparse=True) + sage: LaurentPolynomialRing(QQ, 'y', 3, sparse=True) # optional - sage.modules Multivariate Laurent Polynomial Ring in y0, y1, y2 over Rational Field By calling the :meth:`~sage.structure.category_object.CategoryObject.inject_variables` method, all those variable names are available for interactive use:: - sage: R = LaurentPolynomialRing(GF(7),15,'w'); R - Multivariate Laurent Polynomial Ring in w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14 over Finite Field of size 7 - sage: R.inject_variables() + sage: R = LaurentPolynomialRing(GF(7), 15, 'w'); R # optional - sage.modules sage.rings.finite_rings + Multivariate Laurent Polynomial Ring in w0, w1, w2, w3, w4, w5, w6, w7, + w8, w9, w10, w11, w12, w13, w14 over Finite Field of size 7 + sage: R.inject_variables() # optional - sage.modules sage.rings.finite_rings Defining w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14 - sage: (w0 + 2*w8 + w13)^2 + sage: (w0 + 2*w8 + w13)^2 # optional - sage.modules sage.rings.finite_rings w0^2 + 4*w0*w8 + 4*w8^2 + 2*w0*w13 + 4*w8*w13 + w13^2 """ from sage.rings.polynomial.polynomial_ring import is_PolynomialRing @@ -350,12 +353,12 @@ def _split_laurent_polynomial_dict_(P, M, d): TESTS:: - sage: L.<a, b, c, d> = LaurentPolynomialRing(ZZ) - sage: M = LaurentPolynomialRing(ZZ, 'c, d') - sage: N = LaurentPolynomialRing(M, 'a, b') - sage: M(c/d + 1/c) # indirect doctest + sage: L.<a, b, c, d> = LaurentPolynomialRing(ZZ) # optional - sage.modules + sage: M = LaurentPolynomialRing(ZZ, 'c, d') # optional - sage.modules + sage: N = LaurentPolynomialRing(M, 'a, b') # optional - sage.modules + sage: M(c/d + 1/c) # indirect doctest # optional - sage.modules c*d^-1 + c^-1 - sage: N(a + b/c/d + 1/b) # indirect doctest + sage: N(a + b/c/d + 1/b) # indirect doctest # optional - sage.modules a + (c^-1*d^-1)*b + b^-1 """ vars_P = P.variable_names() @@ -407,10 +410,10 @@ def from_fraction_field(L, x): EXAMPLES:: sage: from sage.rings.polynomial.laurent_polynomial_ring import from_fraction_field - sage: L.<x, y> = LaurentPolynomialRing(ZZ) - sage: F = L.fraction_field() - sage: xi = F(~x) - sage: from_fraction_field(L, xi) == ~x + sage: L.<x, y> = LaurentPolynomialRing(ZZ) # optional - sage.modules + sage: F = L.fraction_field() # optional - sage.modules + sage: xi = F(~x) # optional - sage.modules + sage: from_fraction_field(L, xi) == ~x # optional - sage.modules True """ d = L(x.denominator()) @@ -477,22 +480,22 @@ def _element_constructor_(self, x): sage: U = LaurentPolynomialRing(QQ, 'a') sage: V = LaurentPolynomialRing(QQ, 'c') sage: L.<a, b, c, d> = LaurentPolynomialRing(QQ) - sage: M = LaurentPolynomialRing(QQ, 'c, d') - sage: Mc, Md = M.gens() - sage: N = LaurentPolynomialRing(M, 'a, b') - sage: Na, Nb = N.gens() - sage: U(Na) + sage: M = LaurentPolynomialRing(QQ, 'c, d') # optional - sage.modules + sage: Mc, Md = M.gens() # optional - sage.modules + sage: N = LaurentPolynomialRing(M, 'a, b') # optional - sage.modules + sage: Na, Nb = N.gens() # optional - sage.modules + sage: U(Na) # optional - sage.modules a - sage: V(Mc) + sage: V(Mc) # optional - sage.modules c - sage: M(L(0)) + sage: M(L(0)) # optional - sage.modules 0 - sage: N(L(0)) + sage: N(L(0)) # optional - sage.modules 0 - sage: L(M(0)) + sage: L(M(0)) # optional - sage.modules 0 - sage: L(N(0)) + sage: L(N(0)) # optional - sage.modules 0 :: @@ -504,8 +507,8 @@ def _element_constructor_(self, x): sage: C.<c> = LaurentPolynomialRing(B) sage: B(C(b)) b - sage: D.<d, e> = LaurentPolynomialRing(B) - sage: B(D(b)) + sage: D.<d, e> = LaurentPolynomialRing(B) # optional - sage.modules + sage: B(D(b)) # optional - sage.modules b TESTS: @@ -574,11 +577,11 @@ def __init__(self, R): """ EXAMPLES:: - sage: L = LaurentPolynomialRing(QQ,2,'x') - sage: type(L) + sage: L = LaurentPolynomialRing(QQ,2,'x') # optional - sage.modules + sage: type(L) # optional - sage.modules <class 'sage.rings.polynomial.laurent_polynomial_ring.LaurentPolynomialRing_mpair_with_category'> - sage: L == loads(dumps(L)) + sage: L == loads(dumps(L)) # optional - sage.modules True """ if R.ngens() <= 0: @@ -593,9 +596,9 @@ def _repr_(self): """ TESTS:: - sage: LaurentPolynomialRing(QQ,2,'x').__repr__() + sage: LaurentPolynomialRing(QQ,2,'x').__repr__() # optional - sage.modules 'Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field' - sage: LaurentPolynomialRing(QQ,1,'x').__repr__() + sage: LaurentPolynomialRing(QQ,1,'x').__repr__() # optional - sage.modules 'Multivariate Laurent Polynomial Ring in x over Rational Field' """ return "Multivariate Laurent Polynomial Ring in %s over %s"%(", ".join(self._R.variable_names()), self._R.base_ring()) @@ -606,21 +609,21 @@ def monomial(self, *args): EXAMPLES:: - sage: L = LaurentPolynomialRing(QQ, 'x', 2) - sage: L.monomial(-3, 5) + sage: L = LaurentPolynomialRing(QQ, 'x', 2) # optional - sage.modules + sage: L.monomial(-3, 5) # optional - sage.modules x0^-3*x1^5 - sage: L.monomial(1, 1) + sage: L.monomial(1, 1) # optional - sage.modules x0*x1 - sage: L.monomial(0, 0) + sage: L.monomial(0, 0) # optional - sage.modules 1 - sage: L.monomial(-2, -3) + sage: L.monomial(-2, -3) # optional - sage.modules x0^-2*x1^-3 - sage: x0, x1 = L.gens() - sage: L.monomial(-1, 2) == x0^-1 * x1^2 + sage: x0, x1 = L.gens() # optional - sage.modules + sage: L.monomial(-1, 2) == x0^-1 * x1^2 # optional - sage.modules True - sage: L.monomial(1, 2, 3) + sage: L.monomial(1, 2, 3) # optional - sage.modules Traceback (most recent call last): ... TypeError: tuple key must have same length as ngens @@ -636,96 +639,96 @@ def _element_constructor_(self, x, mon=None): """ EXAMPLES:: - sage: L = LaurentPolynomialRing(QQ,2,'x') - sage: L(1/2) + sage: L = LaurentPolynomialRing(QQ,2,'x') # optional - sage.modules + sage: L(1/2) # optional - sage.modules 1/2 - sage: M = LaurentPolynomialRing(QQ, 'x, y') - sage: var('x, y') + sage: M = LaurentPolynomialRing(QQ, 'x, y') # optional - sage.modules + sage: var('x, y') # optional - sage.modules (x, y) - sage: M(x/y + 3/x) + sage: M(x/y + 3/x) # optional - sage.modules x*y^-1 + 3*x^-1 :: - sage: M(exp(x)) + sage: M(exp(x)) # optional - sage.modules Traceback (most recent call last): ... TypeError: unable to convert e^x to a rational :: - sage: L.<a, b, c, d> = LaurentPolynomialRing(QQ) - sage: M = LaurentPolynomialRing(QQ, 'c, d') - sage: Mc, Md = M.gens() - sage: N = LaurentPolynomialRing(M, 'a, b') - sage: Na, Nb = N.gens() - sage: M(c/d) + sage: L.<a, b, c, d> = LaurentPolynomialRing(QQ) # optional - sage.modules + sage: M = LaurentPolynomialRing(QQ, 'c, d') # optional - sage.modules + sage: Mc, Md = M.gens() # optional - sage.modules + sage: N = LaurentPolynomialRing(M, 'a, b') # optional - sage.modules + sage: Na, Nb = N.gens() # optional - sage.modules + sage: M(c/d) # optional - sage.modules c*d^-1 - sage: N(a*b/c/d) + sage: N(a*b/c/d) # optional - sage.modules (c^-1*d^-1)*a*b - sage: N(c/d) + sage: N(c/d) # optional - sage.modules c*d^-1 - sage: L(Mc) + sage: L(Mc) # optional - sage.modules c - sage: L(Nb) + sage: L(Nb) # optional - sage.modules b - sage: M(L(0)) + sage: M(L(0)) # optional - sage.modules 0 - sage: N(L(0)) + sage: N(L(0)) # optional - sage.modules 0 - sage: L(M(0)) + sage: L(M(0)) # optional - sage.modules 0 - sage: L(N(0)) + sage: L(N(0)) # optional - sage.modules 0 sage: U = LaurentPolynomialRing(QQ, 'a') sage: Ua = U.gen() sage: V = LaurentPolynomialRing(QQ, 'c') sage: Vc = V.gen() - sage: L(Ua) + sage: L(Ua) # optional - sage.modules a - sage: L(Vc) + sage: L(Vc) # optional - sage.modules c - sage: N(Ua) + sage: N(Ua) # optional - sage.modules a - sage: M(Vc) + sage: M(Vc) # optional - sage.modules c - sage: P = LaurentPolynomialRing(QQ, 'a, b') - sage: Q = LaurentPolynomialRing(P, 'c, d') - sage: Q(P.0) + sage: P = LaurentPolynomialRing(QQ, 'a, b') # optional - sage.modules + sage: Q = LaurentPolynomialRing(P, 'c, d') # optional - sage.modules + sage: Q(P.0) # optional - sage.modules a :: sage: A.<a> = LaurentPolynomialRing(QQ) sage: B.<b> = LaurentPolynomialRing(A) - sage: C = LaurentPolynomialRing(QQ, 'a, b') - sage: C(B({1: a})) + sage: C = LaurentPolynomialRing(QQ, 'a, b') # optional - sage.modules + sage: C(B({1: a})) # optional - sage.modules a*b - sage: D.<d, e> = LaurentPolynomialRing(B) - sage: F.<f, g> = LaurentPolynomialRing(D) - sage: D(F(d*e)) + sage: D.<d, e> = LaurentPolynomialRing(B) # optional - sage.modules + sage: F.<f, g> = LaurentPolynomialRing(D) # optional - sage.modules + sage: D(F(d*e)) # optional - sage.modules d*e :: sage: from sage.rings.polynomial.polydict import ETuple - sage: R.<x,y,z> = LaurentPolynomialRing(QQ) - sage: mon = ETuple({}, int(3)) - sage: P = R.polynomial_ring() - sage: R(sum(P.gens()), mon) + sage: R.<x,y,z> = LaurentPolynomialRing(QQ) # optional - sage.modules + sage: mon = ETuple({}, int(3)) # optional - sage.modules + sage: P = R.polynomial_ring() # optional - sage.modules + sage: R(sum(P.gens()), mon) # optional - sage.modules x + y + z - sage: R(sum(P.gens()), (-1,-1,-1)) + sage: R(sum(P.gens()), (-1,-1,-1)) # optional - sage.modules y^-1*z^-1 + x^-1*z^-1 + x^-1*y^-1 :: - sage: RL = R.localization(x+1) - sage: xi = RL(~x) - sage: R(xi) == ~x # indirect doctests + sage: RL = R.localization(x+1) # optional - sage.modules + sage: xi = RL(~x) # optional - sage.modules + sage: R(xi) == ~x # indirect doctests # optional - sage.modules True """ from sage.structure.element import Expression @@ -782,8 +785,8 @@ def __reduce__(self): EXAMPLES:: - sage: L = LaurentPolynomialRing(QQ, 2, 'x') - sage: loads(dumps(L)) == L + sage: L = LaurentPolynomialRing(QQ, 2, 'x') # optional - sage.modules + sage: loads(dumps(L)) == L # optional - sage.modules True """ return LaurentPolynomialRing_mpair, (self._R,) diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index 2422521fba8..cfac856258a 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -1416,7 +1416,7 @@ cdef class PowerSeries(AlgebraElement): Another example:: - sage: (exp(t)).stieltjes_continued_fraction() + sage: (exp(t)).stieltjes_continued_fraction() # optional - sage.symbolic (1, -1/2, 1/6, @@ -1866,7 +1866,7 @@ cdef class PowerSeries(AlgebraElement): one raises an error:: sage: g = 2+f - sage: cos(g) + sage: cos(g) # optional - sage.symbolic Traceback (most recent call last): ... ValueError: can only apply cos to formal power series with zero constant term @@ -1951,7 +1951,7 @@ cdef class PowerSeries(AlgebraElement): one raises an error:: sage: g = 2+f - sage: sin(g) + sage: sin(g) # optional - sage.symbolic Traceback (most recent call last): ... ValueError: can only apply sin to formal power series with zero constant term From 986e3b8a65d4b796df36868ffe21be053923039d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe <mkoeppe@math.ucdavis.edu> Date: Sun, 23 Apr 2023 22:20:43 -0700 Subject: [PATCH 7/8] src/sage/combinat/root_system/root_lattice_realization_algebras.py: Update doctest output --- .../combinat/root_system/root_lattice_realization_algebras.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/root_system/root_lattice_realization_algebras.py b/src/sage/combinat/root_system/root_lattice_realization_algebras.py index 3e70a2e8fd9..71059e21548 100644 --- a/src/sage/combinat/root_system/root_lattice_realization_algebras.py +++ b/src/sage/combinat/root_system/root_lattice_realization_algebras.py @@ -1166,13 +1166,13 @@ def expand(self, alphabet): TESTS:: sage: type(p.expand(F.gens())) - <class 'sage.rings.polynomial.laurent_polynomial.LaurentPolynomial_mpair'> + <class 'sage.rings.polynomial.laurent_polynomial_mpair.LaurentPolynomial_mpair'> sage: p = KL.zero() sage: p.expand(F.gens()) 0 sage: type(p.expand(F.gens())) - <class 'sage.rings.polynomial.laurent_polynomial.LaurentPolynomial_mpair'> + <class 'sage.rings.polynomial.laurent_polynomial_mpair.LaurentPolynomial_mpair'> """ codomain = alphabet[0].parent() return codomain.sum(c * prod(X**int(n) From b9bf5bbe02e8de5e87e069925ab82d14c1922e9e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe <mkoeppe@math.ucdavis.edu> Date: Fri, 2 Jun 2023 11:04:02 -0700 Subject: [PATCH 8/8] src/sage/rings/lazy_series.py: Add # optional - sage.rings.number_field --- src/sage/rings/lazy_series.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index f5440ead30e..d1647ec445f 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -175,9 +175,9 @@ sage: check(L, lambda n: n, valuation=-5) # optional - sage.rings.finite_rings sage: check(L, gen(), valuation=-5) # optional - sage.rings.finite_rings - sage: L = LazyDirichletSeriesRing(QQbar, "s") - sage: check(L, lambda n: n, valuation=2) - sage: check(L, gen(), valuation=2) + sage: L = LazyDirichletSeriesRing(QQbar, "s") # optional - sage.rings.number_field + sage: check(L, lambda n: n, valuation=2) # optional - sage.rings.number_field + sage: check(L, gen(), valuation=2) # optional - sage.rings.number_field sage: L.<z> = LazyPowerSeriesRing(GF(2)) # optional - sage.rings.finite_rings sage: check(L, lambda n: n, valuation=0) # optional - sage.rings.finite_rings @@ -296,9 +296,9 @@ def __init__(self, parent, coeff_stream): sage: L.<z> = LazyLaurentSeriesRing(ZZ) sage: TestSuite(L.an_element()).run() - sage: L = LazyDirichletSeriesRing(QQbar, 'z') - sage: g = L(constant=1) - sage: TestSuite(g).run() + sage: L = LazyDirichletSeriesRing(QQbar, 'z') # optional - sage.rings.number_field + sage: g = L(constant=1) # optional - sage.rings.number_field + sage: TestSuite(g).run() # optional - sage.rings.number_field """ Element.__init__(self, parent) self._coeff_stream = coeff_stream