diff --git a/src/doc/en/reference/polynomial_rings/index.rst b/src/doc/en/reference/polynomial_rings/index.rst index 8a8ef70563c..b03fa4279ca 100644 --- a/src/doc/en/reference/polynomial_rings/index.rst +++ b/src/doc/en/reference/polynomial_rings/index.rst @@ -45,6 +45,7 @@ Laurent Polynomials .. toctree:: :maxdepth: 1 + sage/rings/polynomial/laurent_polynomial_ring_base sage/rings/polynomial/laurent_polynomial_ring sage/rings/polynomial/laurent_polynomial sage/rings/polynomial/omega diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 6c5b08e003a..6ff8c5bc609 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1760,9 +1760,10 @@ def _apply_functor(self, R): Multivariate Laurent Polynomial Ring in s, t over Rational Field """ - from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing, is_LaurentPolynomialRing - if self.multi_variate and is_LaurentPolynomialRing(R): - return LaurentPolynomialRing(R.base_ring(), (list(R.variable_names()) + [self.var])) + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic + if self.multi_variate and isinstance(R, LaurentPolynomialRing_generic): + return LaurentPolynomialRing(R.base_ring(), list(R.variable_names()) + [self.var]) else: return LaurentPolynomialRing(R, self.var) diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index 3f1964b13d2..41c20d2a5ab 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -313,7 +313,7 @@ def _coerce_map_from_(self, S): """ from sage.rings.rational_field import QQ from sage.rings.number_field.number_field_base import NumberField - from sage.rings.polynomial.laurent_polynomial_ring import \ + from sage.rings.polynomial.laurent_polynomial_ring_base import \ LaurentPolynomialRing_generic if S is self._R: diff --git a/src/sage/rings/laurent_series_ring.py b/src/sage/rings/laurent_series_ring.py index be921f22154..56551b50a55 100644 --- a/src/sage/rings/laurent_series_ring.py +++ b/src/sage/rings/laurent_series_ring.py @@ -623,9 +623,10 @@ def _coerce_map_from_(self, P): A = self.base_ring() from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.power_series_ring import is_PowerSeriesRing - from sage.rings.polynomial.laurent_polynomial_ring import is_LaurentPolynomialRing + from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic + if ((is_LaurentSeriesRing(P) or - is_LaurentPolynomialRing(P) or + isinstance(P, LaurentPolynomialRing_generic) or is_PowerSeriesRing(P) or is_PolynomialRing(P)) and P.variable_name() == self.variable_name() diff --git a/src/sage/rings/localization.py b/src/sage/rings/localization.py index 8d46e8f4475..138ac172745 100644 --- a/src/sage/rings/localization.py +++ b/src/sage/rings/localization.py @@ -669,8 +669,9 @@ def __init__(self, base_ring, extra_units, names=None, normalize=True, category= if not type(extra_units) is list: extra_units = [extra_units] - from sage.rings.polynomial.laurent_polynomial_ring import is_LaurentPolynomialRing - if is_LaurentPolynomialRing(base_ring): + from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic + + if isinstance(base_ring, LaurentPolynomialRing_generic): extra_units += list(base_ring.gens()) base_ring = base_ring.polynomial_ring() diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 0ec8ecb15f7..aaa1166b9d2 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -43,14 +43,10 @@ # **************************************************************************** from sage.structure.element import parent -from sage.structure.parent import Parent -from sage.rings.infinity import infinity -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.misc.latex import latex from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial_mpair, LaurentPolynomial_univariate -from sage.rings.ring import CommutativeRing +from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -import sage.rings.polynomial.laurent_polynomial_ideal as lp_ideal def is_LaurentPolynomialRing(R): """ @@ -59,16 +55,26 @@ def is_LaurentPolynomialRing(R): EXAMPLES:: sage: from sage.rings.polynomial.laurent_polynomial_ring import is_LaurentPolynomialRing - sage: P = PolynomialRing(QQ,2,'x') + sage: P = PolynomialRing(QQ, 2, 'x') sage: is_LaurentPolynomialRing(P) + doctest:warning... + DeprecationWarning: is_LaurentPolynomialRing is deprecated; use isinstance(..., + sage.rings.polynomial.laurent_polynomial_ring_base.LaurentPolynomialRing_generic) instead + See https://github.com/sagemath/sage/issues/35229 for details. False sage: R = LaurentPolynomialRing(QQ,3,'x') sage: is_LaurentPolynomialRing(R) True """ + from sage.misc.superseded import deprecation + deprecation(35229, + "is_LaurentPolynomialRing is deprecated; use " + "isinstance(..., sage.rings.polynomial.laurent_polynomial_ring_base." + "LaurentPolynomialRing_generic) instead") return isinstance(R, LaurentPolynomialRing_generic) + _cache = {} def LaurentPolynomialRing(base_ring, *args, **kwds): r""" @@ -413,495 +419,6 @@ def from_fraction_field(L, x): else: raise TypeError("fraction must have unit denominator") -class LaurentPolynomialRing_generic(CommutativeRing, Parent): - """ - Laurent polynomial ring (base class). - - EXAMPLES: - - This base class inherits from :class:`~sage.rings.ring.CommutativeRing`. - Since :trac:`11900`, it is also initialised as such:: - - sage: R. = LaurentPolynomialRing(QQ) - sage: R.category() - Join of Category of unique factorization domains and Category of commutative algebras over (number fields and quotient fields and metric spaces) and Category of infinite sets - sage: TestSuite(R).run() - - """ - def __init__(self, R): - """ - EXAMPLES:: - - sage: R = LaurentPolynomialRing(QQ,2,'x') - sage: R == loads(dumps(R)) - True - """ - self._n = R.ngens() - self._R = R - names = R.variable_names() - self._one_element = self.element_class(self, R.one()) - CommutativeRing.__init__(self, R.base_ring(), names=names, - category=R.category()) - - def ngens(self): - """ - Return the number of generators of ``self``. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').ngens() - 2 - sage: LaurentPolynomialRing(QQ,1,'x').ngens() - 1 - """ - return self._n - - def gen(self, i=0): - r""" - Returns the `i^{th}` generator of self. If i is not specified, then - the first generator will be returned. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').gen() - x0 - sage: LaurentPolynomialRing(QQ,2,'x').gen(0) - x0 - sage: LaurentPolynomialRing(QQ,2,'x').gen(1) - x1 - - TESTS:: - - sage: LaurentPolynomialRing(QQ,2,'x').gen(3) - Traceback (most recent call last): - ... - ValueError: generator not defined - """ - if i < 0 or i >= self._n: - raise ValueError("generator not defined") - try: - return self.__generators[i] - except AttributeError: - self.__generators = tuple(self(x) for x in self._R.gens()) - return self.__generators[i] - - - def variable_names_recursive(self, depth=infinity): - r""" - Return the list of variable names of this ring and its base rings, - as if it were a single multi-variate Laurent polynomial. - - INPUT: - - - ``depth`` -- an integer or :mod:`Infinity `. - - OUTPUT: - - A tuple of strings. - - EXAMPLES:: - - sage: T = LaurentPolynomialRing(QQ, 'x') - sage: S = LaurentPolynomialRing(T, 'y') - sage: R = LaurentPolynomialRing(S, 'z') - sage: R.variable_names_recursive() - ('x', 'y', 'z') - sage: R.variable_names_recursive(2) - ('y', 'z') - """ - if depth <= 0: - return () - if depth == 1: - return self.variable_names() - my_vars = self.variable_names() - try: - return self.base_ring().variable_names_recursive(depth - len(my_vars)) + my_vars - except AttributeError: - return my_vars - - def is_integral_domain(self, proof=True): - """ - Returns True if self is an integral domain. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').is_integral_domain() - True - - The following used to fail; see :trac:`7530`:: - - sage: L = LaurentPolynomialRing(ZZ, 'X') - sage: L['Y'] - Univariate Polynomial Ring in Y over Univariate Laurent Polynomial Ring in X over Integer Ring - """ - return self.base_ring().is_integral_domain(proof) - - def is_noetherian(self): - """ - Returns True if self is Noetherian. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').is_noetherian() - Traceback (most recent call last): - ... - NotImplementedError - """ - raise NotImplementedError - - def construction(self): - """ - Return the construction of ``self``. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x,y').construction() - (LaurentPolynomialFunctor, - Univariate Laurent Polynomial Ring in x over Rational Field) - - """ - from sage.categories.pushout import LaurentPolynomialFunctor - vars = self.variable_names() - if len(vars) == 1: - return LaurentPolynomialFunctor(vars[0], False), self.base_ring() - else: - return LaurentPolynomialFunctor(vars[-1], True), LaurentPolynomialRing(self.base_ring(), vars[:-1]) - - def completion(self, p, prec=20, extras=None): - """ - EXAMPLES:: - - sage: P.=LaurentPolynomialRing(QQ) - sage: P - Univariate Laurent Polynomial Ring in x over Rational Field - sage: PP=P.completion(x) - sage: PP - Laurent Series Ring in x over Rational Field - sage: f=1-1/x - sage: PP(f) - -x^-1 + 1 - sage: 1/PP(f) - -x - x^2 - x^3 - x^4 - x^5 - x^6 - x^7 - x^8 - x^9 - x^10 - x^11 - x^12 - x^13 - x^14 - x^15 - x^16 - x^17 - x^18 - x^19 - x^20 + O(x^21) - - TESTS: - - Check that the precision is taken into account (:trac:`24431`):: - - sage: L = LaurentPolynomialRing(QQ, 'x') - sage: L.completion('x', 100).default_prec() - 100 - sage: L.completion('x', 20).default_prec() - 20 - """ - if str(p) == self._names[0] and self._n == 1: - from sage.rings.laurent_series_ring import LaurentSeriesRing - R = self.polynomial_ring().completion(self._names[0], prec) - return LaurentSeriesRing(R) - else: - raise TypeError("Cannot complete %s with respect to %s" % (self, p)) - - def remove_var(self, var): - """ - EXAMPLES:: - - sage: R = LaurentPolynomialRing(QQ,'x,y,z') - sage: R.remove_var('x') - Multivariate Laurent Polynomial Ring in y, z over Rational Field - sage: R.remove_var('x').remove_var('y') - Univariate Laurent Polynomial Ring in z over Rational Field - """ - vars = list(self.variable_names()) - vars.remove(str(var)) - return LaurentPolynomialRing(self.base_ring(), vars) - - def _coerce_map_from_(self, R): - """ - EXAMPLES:: - - sage: L. = LaurentPolynomialRing(QQ) - sage: L.coerce_map_from(QQ) - Generic morphism: - From: Rational Field - To: Multivariate Laurent Polynomial Ring in x, y over Rational Field - - Let us check that coercion between Laurent Polynomials over - different base rings works (:trac:`15345`):: - - sage: R = LaurentPolynomialRing(ZZ, 'x') - sage: T = LaurentPolynomialRing(QQ, 'x') - sage: R.gen() + 3*T.gen() - 4*x - """ - if R is self._R: - return self._generic_coerce_map(R) - f = self._coerce_map_via([self._R], R) - if f is not None: - return f - if (isinstance(R, LaurentPolynomialRing_generic) - and self._R.has_coerce_map_from(R._R)): - return self._generic_coerce_map(R) - - def __eq__(self, right): - """ - Check whether ``self`` is equal to ``right``. - - EXAMPLES:: - - sage: R = LaurentPolynomialRing(QQ,'x,y,z') - sage: P = LaurentPolynomialRing(ZZ,'x,y,z') - sage: Q = LaurentPolynomialRing(QQ,'x,y') - - sage: R == R - True - sage: R == Q - False - sage: Q == P - False - sage: P == R - False - """ - if type(self) != type(right): - return False - return self._R == right._R - - def __ne__(self, other): - """ - Check whether ``self`` is not equal to ``other``. - - EXAMPLES:: - - sage: R = LaurentPolynomialRing(QQ,'x,y,z') - sage: P = LaurentPolynomialRing(ZZ,'x,y,z') - sage: Q = LaurentPolynomialRing(QQ,'x,y') - - sage: R != R - False - sage: R != Q - True - sage: Q != P - True - sage: P != R - True - """ - return not (self == other) - - def __hash__(self): - """ - Return the hash of ``self``. - - EXAMPLES:: - - sage: h1 = hash(LaurentPolynomialRing(ZZ,'x,y,z')) - sage: h2 = hash(LaurentPolynomialRing(ZZ,'x,y,z')) - sage: h3 = hash(LaurentPolynomialRing(QQ,'x,y,z')) - sage: h4 = hash(LaurentPolynomialRing(ZZ,'x,y')) - sage: h1 == h2 and h1 != h3 and h1 != h4 - True - """ - return hash(self._R) ^ 12059065606945654693 - - def _latex_(self): - r""" - EXAMPLES:: - - sage: latex(LaurentPolynomialRing(QQ,2,'x')) - \Bold{Q}[x_{0}^{\pm 1}, x_{1}^{\pm 1}] - """ - vars = ', '.join(a + r'^{\pm 1}' for a in self.latex_variable_names()) - return "%s[%s]" % (latex(self.base_ring()), vars) - - def _ideal_class_(self, n=0): - """ - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x')._ideal_class_() - Traceback (most recent call last): - ... - NotImplementedError - """ - # One may eventually want ideal classes in these guys. - raise NotImplementedError - - def ideal(self, *args, **kwds): - """ - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').ideal([1]) - Ideal (1) of Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field - - TESTS: - - check that :trac:`26421` is fixed:: - - sage: R. = LaurentPolynomialRing(ZZ) - sage: P. = PolynomialRing(R) - sage: p = x-t - sage: p.content_ideal() # indirect doctest - Ideal (-t, 1) of Univariate Laurent Polynomial Ring in t over Integer Ring - """ - return lp_ideal.LaurentPolynomialIdeal(self, *args, **kwds) - - def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): - """ - EXAMPLES:: - - sage: T. = ZZ[] - sage: K. = NumberField(t^2 + 1) - sage: L. = LaurentPolynomialRing(K) - sage: L._is_valid_homomorphism_(K, (K(1/2), K(3/2))) - True - sage: Q5 = Qp(5); i5 = Q5(-1).sqrt() - sage: L._is_valid_homomorphism_(Q5, (Q5(1/2), Q5(3/2))) # no coercion - False - sage: L._is_valid_homomorphism_(Q5, (Q5(1/2), Q5(3/2)), base_map=K.hom([i5])) - True - """ - if base_map is None and not codomain.has_coerce_map_from(self.base_ring()): - # we need that elements of the base ring - # canonically coerce into codomain. - return False - for a in im_gens: - # in addition, the image of each generator must be invertible. - if not a.is_unit(): - return False - return True - - def term_order(self): - """ - Returns the term order of self. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').term_order() - Degree reverse lexicographic term order - - """ - return self._R.term_order() - - def is_finite(self): - """ - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').is_finite() - False - - """ - return False - - def is_field(self, proof = True): - """ - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').is_field() - False - """ - return False - - def polynomial_ring(self): - """ - Returns the polynomial ring associated with self. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').polynomial_ring() - Multivariate Polynomial Ring in x0, x1 over Rational Field - sage: LaurentPolynomialRing(QQ,1,'x').polynomial_ring() - Multivariate Polynomial Ring in x over Rational Field - """ - return self._R - - def characteristic(self): - """ - Returns the characteristic of the base ring. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').characteristic() - 0 - sage: LaurentPolynomialRing(GF(3),2,'x').characteristic() - 3 - - """ - return self.base_ring().characteristic() - - def krull_dimension(self): - """ - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').krull_dimension() - Traceback (most recent call last): - ... - NotImplementedError - """ - raise NotImplementedError - - def random_element(self, low_degree = -2, high_degree = 2, terms = 5, choose_degree=False,*args, **kwds): - """ - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').random_element() - Traceback (most recent call last): - ... - NotImplementedError - """ - raise NotImplementedError - - def is_exact(self): - """ - Returns True if the base ring is exact. - - EXAMPLES:: - - sage: LaurentPolynomialRing(QQ,2,'x').is_exact() - True - sage: LaurentPolynomialRing(RDF,2,'x').is_exact() - False - """ - return self.base_ring().is_exact() - - def change_ring(self, base_ring=None, names=None, sparse=False, order=None): - """ - EXAMPLES:: - - sage: R = LaurentPolynomialRing(QQ,2,'x') - sage: R.change_ring(ZZ) - Multivariate Laurent Polynomial Ring in x0, x1 over Integer Ring - - Check that the distinction between a univariate ring and a multivariate ring with one - generator is preserved:: - - sage: P. = LaurentPolynomialRing(QQ, 1) - sage: P - Multivariate Laurent Polynomial Ring in x over Rational Field - sage: K. = CyclotomicField(4) - sage: P.change_ring(K) - Multivariate Laurent Polynomial Ring in x over Cyclotomic Field of order 4 and degree 2 - """ - if base_ring is None: - base_ring = self.base_ring() - if names is None: - names = self.variable_names() - if isinstance(self, LaurentPolynomialRing_univariate): - return LaurentPolynomialRing(base_ring, names[0], sparse = sparse) - - if order is None: - order = self.polynomial_ring().term_order() - return LaurentPolynomialRing(base_ring, self._n, names, order = order) - - def fraction_field(self): - """ - The fraction field is the same as the fraction field of the - polynomial ring. - - EXAMPLES:: - - sage: L. = LaurentPolynomialRing(QQ) - sage: L.fraction_field() - Fraction Field of Univariate Polynomial Ring in x over Rational Field - sage: (x^-1 + 2) / (x - 1) - (2*x + 1)/(x^2 - x) - """ - return self.polynomial_ring().fraction_field() class LaurentPolynomialRing_univariate(LaurentPolynomialRing_generic): def __init__(self, R): @@ -1050,6 +567,7 @@ def __reduce__(self): """ return LaurentPolynomialRing_univariate, (self._R,) + class LaurentPolynomialRing_mpair(LaurentPolynomialRing_generic): def __init__(self, R): """ diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py new file mode 100644 index 00000000000..4a52bb965fc --- /dev/null +++ b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py @@ -0,0 +1,530 @@ +# sage.doctest: optional - sage.modules +r""" +Ring of Laurent Polynomials (base class) + +If `R` is a commutative ring, then the ring of Laurent polynomials in `n` +variables over `R` is `R[x_1^{\pm 1}, x_2^{\pm 1}, \ldots, x_n^{\pm 1}]`. + +AUTHORS: + +- David Roe (2008-2-23): created +- David Loeffler (2009-07-10): cleaned up docstrings +""" +# **************************************************************************** +# Copyright (C) 2008 David Roe , +# William Stein , +# Mike Hansen +# Vincent Delecroix <20100.delecroix@gmail.com> +# +# 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.infinity import infinity +from sage.rings.ring import CommutativeRing +from sage.structure.parent import Parent + + +class LaurentPolynomialRing_generic(CommutativeRing, Parent): + """ + Laurent polynomial ring (base class). + + EXAMPLES: + + This base class inherits from :class:`~sage.rings.ring.CommutativeRing`. + Since :trac:`11900`, it is also initialised as such:: + + sage: R. = LaurentPolynomialRing(QQ) + sage: R.category() + Join of Category of unique factorization domains and Category of commutative algebras over (number fields and quotient fields and metric spaces) and Category of infinite sets + sage: TestSuite(R).run() + + """ + def __init__(self, R): + """ + EXAMPLES:: + + sage: R = LaurentPolynomialRing(QQ,2,'x') + sage: R == loads(dumps(R)) + True + """ + self._n = R.ngens() + self._R = R + names = R.variable_names() + self._one_element = self.element_class(self, R.one()) + CommutativeRing.__init__(self, R.base_ring(), names=names, + category=R.category()) + + def ngens(self): + """ + Return the number of generators of ``self``. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x').ngens() + 2 + sage: LaurentPolynomialRing(QQ,1,'x').ngens() + 1 + """ + return self._n + + def gen(self, i=0): + r""" + Returns the `i^{th}` generator of self. If i is not specified, then + the first generator will be returned. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x').gen() + x0 + sage: LaurentPolynomialRing(QQ,2,'x').gen(0) + x0 + sage: LaurentPolynomialRing(QQ,2,'x').gen(1) + x1 + + TESTS:: + + sage: LaurentPolynomialRing(QQ,2,'x').gen(3) + Traceback (most recent call last): + ... + ValueError: generator not defined + """ + if i < 0 or i >= self._n: + raise ValueError("generator not defined") + try: + return self.__generators[i] + except AttributeError: + self.__generators = tuple(self(x) for x in self._R.gens()) + return self.__generators[i] + + + def variable_names_recursive(self, depth=infinity): + r""" + Return the list of variable names of this ring and its base rings, + as if it were a single multi-variate Laurent polynomial. + + INPUT: + + - ``depth`` -- an integer or :mod:`Infinity `. + + OUTPUT: + + A tuple of strings. + + EXAMPLES:: + + sage: T = LaurentPolynomialRing(QQ, 'x') + sage: S = LaurentPolynomialRing(T, 'y') + sage: R = LaurentPolynomialRing(S, 'z') + sage: R.variable_names_recursive() + ('x', 'y', 'z') + sage: R.variable_names_recursive(2) + ('y', 'z') + """ + if depth <= 0: + return () + if depth == 1: + return self.variable_names() + my_vars = self.variable_names() + try: + return self.base_ring().variable_names_recursive(depth - len(my_vars)) + my_vars + except AttributeError: + return my_vars + + def is_integral_domain(self, proof=True): + """ + Returns True if self is an integral domain. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x').is_integral_domain() + True + + The following used to fail; see :trac:`7530`:: + + sage: L = LaurentPolynomialRing(ZZ, 'X') + sage: L['Y'] + Univariate Polynomial Ring in Y over Univariate Laurent Polynomial Ring in X over Integer Ring + """ + return self.base_ring().is_integral_domain(proof) + + def is_noetherian(self): + """ + Returns True if self is Noetherian. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x').is_noetherian() + Traceback (most recent call last): + ... + NotImplementedError + """ + raise NotImplementedError + + def construction(self): + """ + Return the construction of ``self``. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x,y').construction() + (LaurentPolynomialFunctor, + Univariate Laurent Polynomial Ring in x over Rational Field) + + """ + from sage.categories.pushout import LaurentPolynomialFunctor + from .laurent_polynomial_ring import LaurentPolynomialRing + + vars = self.variable_names() + if len(vars) == 1: + return LaurentPolynomialFunctor(vars[0], False), self.base_ring() + else: + return LaurentPolynomialFunctor(vars[-1], True), LaurentPolynomialRing(self.base_ring(), vars[:-1]) + + def completion(self, p, prec=20, extras=None): + """ + EXAMPLES:: + + sage: P.=LaurentPolynomialRing(QQ) + sage: P + Univariate Laurent Polynomial Ring in x over Rational Field + sage: PP=P.completion(x) + sage: PP + Laurent Series Ring in x over Rational Field + sage: f=1-1/x + sage: PP(f) + -x^-1 + 1 + sage: 1/PP(f) + -x - x^2 - x^3 - x^4 - x^5 - x^6 - x^7 - x^8 - x^9 - x^10 - x^11 - x^12 - x^13 - x^14 - x^15 - x^16 - x^17 - x^18 - x^19 - x^20 + O(x^21) + + TESTS: + + Check that the precision is taken into account (:trac:`24431`):: + + sage: L = LaurentPolynomialRing(QQ, 'x') + sage: L.completion('x', 100).default_prec() + 100 + sage: L.completion('x', 20).default_prec() + 20 + """ + if str(p) == self._names[0] and self._n == 1: + from sage.rings.laurent_series_ring import LaurentSeriesRing + R = self.polynomial_ring().completion(self._names[0], prec) + return LaurentSeriesRing(R) + else: + raise TypeError("Cannot complete %s with respect to %s" % (self, p)) + + def remove_var(self, var): + """ + EXAMPLES:: + + sage: R = LaurentPolynomialRing(QQ,'x,y,z') + sage: R.remove_var('x') + Multivariate Laurent Polynomial Ring in y, z over Rational Field + sage: R.remove_var('x').remove_var('y') + Univariate Laurent Polynomial Ring in z over Rational Field + """ + from .laurent_polynomial_ring import LaurentPolynomialRing + + vars = list(self.variable_names()) + vars.remove(str(var)) + return LaurentPolynomialRing(self.base_ring(), vars) + + def _coerce_map_from_(self, R): + """ + EXAMPLES:: + + sage: L. = LaurentPolynomialRing(QQ) + sage: L.coerce_map_from(QQ) + Generic morphism: + From: Rational Field + To: Multivariate Laurent Polynomial Ring in x, y over Rational Field + + Let us check that coercion between Laurent Polynomials over + different base rings works (:trac:`15345`):: + + sage: R = LaurentPolynomialRing(ZZ, 'x') + sage: T = LaurentPolynomialRing(QQ, 'x') + sage: R.gen() + 3*T.gen() + 4*x + """ + if R is self._R: + return self._generic_coerce_map(R) + f = self._coerce_map_via([self._R], R) + if f is not None: + return f + if (isinstance(R, LaurentPolynomialRing_generic) + and self._R.has_coerce_map_from(R._R)): + return self._generic_coerce_map(R) + + def __eq__(self, right): + """ + Check whether ``self`` is equal to ``right``. + + EXAMPLES:: + + sage: R = LaurentPolynomialRing(QQ,'x,y,z') + sage: P = LaurentPolynomialRing(ZZ,'x,y,z') + sage: Q = LaurentPolynomialRing(QQ,'x,y') + + sage: R == R + True + sage: R == Q + False + sage: Q == P + False + sage: P == R + False + """ + if type(self) != type(right): + return False + return self._R == right._R + + def __ne__(self, other): + """ + Check whether ``self`` is not equal to ``other``. + + EXAMPLES:: + + sage: R = LaurentPolynomialRing(QQ,'x,y,z') + sage: P = LaurentPolynomialRing(ZZ,'x,y,z') + sage: Q = LaurentPolynomialRing(QQ,'x,y') + + sage: R != R + False + sage: R != Q + True + sage: Q != P + True + sage: P != R + True + """ + return not (self == other) + + def __hash__(self): + """ + Return the hash of ``self``. + + EXAMPLES:: + + sage: h1 = hash(LaurentPolynomialRing(ZZ,'x,y,z')) + sage: h2 = hash(LaurentPolynomialRing(ZZ,'x,y,z')) + sage: h3 = hash(LaurentPolynomialRing(QQ,'x,y,z')) + sage: h4 = hash(LaurentPolynomialRing(ZZ,'x,y')) + sage: h1 == h2 and h1 != h3 and h1 != h4 + True + """ + return hash(self._R) ^ 12059065606945654693 + + def _latex_(self): + r""" + EXAMPLES:: + + sage: latex(LaurentPolynomialRing(QQ,2,'x')) + \Bold{Q}[x_{0}^{\pm 1}, x_{1}^{\pm 1}] + """ + from sage.misc.latex import latex + + vars = ', '.join(a + r'^{\pm 1}' for a in self.latex_variable_names()) + return "%s[%s]" % (latex(self.base_ring()), vars) + + def _ideal_class_(self, n=0): + """ + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x')._ideal_class_() + Traceback (most recent call last): + ... + NotImplementedError + """ + # One may eventually want ideal classes in these guys. + raise NotImplementedError + + def ideal(self, *args, **kwds): + """ + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x').ideal([1]) + Ideal (1) of Multivariate Laurent Polynomial Ring in x0, x1 over Rational Field + + TESTS: + + check that :trac:`26421` is fixed:: + + sage: R. = LaurentPolynomialRing(ZZ) + sage: P. = PolynomialRing(R) + sage: p = x-t + sage: p.content_ideal() # indirect doctest + Ideal (-t, 1) of Univariate Laurent Polynomial Ring in t over Integer Ring + """ + from sage.rings.polynomial.laurent_polynomial_ideal import LaurentPolynomialIdeal + return LaurentPolynomialIdeal(self, *args, **kwds) + + def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): + """ + EXAMPLES:: + + sage: T. = ZZ[] + sage: K. = NumberField(t^2 + 1) # optional - sage.rings.number_field + sage: L. = LaurentPolynomialRing(K) # optional - sage.rings.number_field + sage: L._is_valid_homomorphism_(K, (K(1/2), K(3/2))) # optional - sage.rings.number_field + True + sage: Q5 = Qp(5); i5 = Q5(-1).sqrt() # optional - sage.rings.padics + sage: L._is_valid_homomorphism_(Q5, (Q5(1/2), Q5(3/2))) # no coercion # optional - sage.rings.padics + False + sage: L._is_valid_homomorphism_(Q5, (Q5(1/2), Q5(3/2)), base_map=K.hom([i5])) # optional - sage.rings.padics + True + """ + if base_map is None and not codomain.has_coerce_map_from(self.base_ring()): + # we need that elements of the base ring + # canonically coerce into codomain. + return False + for a in im_gens: + # in addition, the image of each generator must be invertible. + if not a.is_unit(): + return False + return True + + def term_order(self): + """ + Returns the term order of self. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x').term_order() + Degree reverse lexicographic term order + + """ + return self._R.term_order() + + def is_finite(self): + """ + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x').is_finite() + False + + """ + return False + + def is_field(self, proof = True): + """ + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x').is_field() + False + """ + return False + + def polynomial_ring(self): + """ + Returns the polynomial ring associated with self. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x').polynomial_ring() + Multivariate Polynomial Ring in x0, x1 over Rational Field + sage: LaurentPolynomialRing(QQ,1,'x').polynomial_ring() + Multivariate Polynomial Ring in x over Rational Field + """ + return self._R + + def characteristic(self): + """ + Returns the characteristic of the base ring. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x').characteristic() + 0 + sage: LaurentPolynomialRing(GF(3), 2, 'x').characteristic() # optional - sage.libs.pari + 3 + + """ + return self.base_ring().characteristic() + + def krull_dimension(self): + """ + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x').krull_dimension() + Traceback (most recent call last): + ... + NotImplementedError + """ + raise NotImplementedError + + def random_element(self, low_degree = -2, high_degree = 2, terms = 5, choose_degree=False,*args, **kwds): + """ + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x').random_element() + Traceback (most recent call last): + ... + NotImplementedError + """ + raise NotImplementedError + + def is_exact(self): + """ + Returns True if the base ring is exact. + + EXAMPLES:: + + sage: LaurentPolynomialRing(QQ,2,'x').is_exact() + True + sage: LaurentPolynomialRing(RDF,2,'x').is_exact() + False + """ + return self.base_ring().is_exact() + + def change_ring(self, base_ring=None, names=None, sparse=False, order=None): + """ + EXAMPLES:: + + sage: R = LaurentPolynomialRing(QQ,2,'x') + sage: R.change_ring(ZZ) + Multivariate Laurent Polynomial Ring in x0, x1 over Integer Ring + + Check that the distinction between a univariate ring and a multivariate ring with one + generator is preserved:: + + sage: P. = LaurentPolynomialRing(QQ, 1) + sage: P + Multivariate Laurent Polynomial Ring in x over Rational Field + sage: K. = CyclotomicField(4) # optional - sage.rings.number_field + sage: P.change_ring(K) # optional - sage.rings.number_field + Multivariate Laurent Polynomial Ring in x over + Cyclotomic Field of order 4 and degree 2 + """ + from .laurent_polynomial_ring import LaurentPolynomialRing, LaurentPolynomialRing_univariate + + if base_ring is None: + base_ring = self.base_ring() + if names is None: + names = self.variable_names() + if isinstance(self, LaurentPolynomialRing_univariate): + return LaurentPolynomialRing(base_ring, names[0], sparse = sparse) + + if order is None: + order = self.polynomial_ring().term_order() + return LaurentPolynomialRing(base_ring, self._n, names, order = order) + + def fraction_field(self): + """ + The fraction field is the same as the fraction field of the + polynomial ring. + + EXAMPLES:: + + sage: L. = LaurentPolynomialRing(QQ) + sage: L.fraction_field() + Fraction Field of Univariate Polynomial Ring in x over Rational Field + sage: (x^-1 + 2) / (x - 1) + (2*x + 1)/(x^2 - x) + """ + return self.polynomial_ring().fraction_field() diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index f1547a92301..a0c497dc65d 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -213,7 +213,7 @@ cdef class SymbolicRing(sage.rings.abc.SymbolicRing): from sage.rings.complex_arb import ComplexBallField from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing - from sage.rings.polynomial.laurent_polynomial_ring import is_LaurentPolynomialRing + from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic from sage.rings.complex_mpfr import ComplexField from sage.rings.infinity import InfinityRing, UnsignedInfinityRing from sage.rings.real_lazy import RLF, CLF @@ -226,7 +226,7 @@ cdef class SymbolicRing(sage.rings.abc.SymbolicRing): if R._is_numerical(): # Almost anything with a coercion into any precision of CC return R not in (RLF, CLF) - elif is_PolynomialRing(R) or is_MPolynomialRing(R) or is_FractionField(R) or is_LaurentPolynomialRing(R): + elif is_PolynomialRing(R) or is_MPolynomialRing(R) or is_FractionField(R) or isinstance(R, LaurentPolynomialRing_generic): base = R.base_ring() return base is not self and self.has_coerce_map_from(base) elif (R is InfinityRing or R is UnsignedInfinityRing