Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
r""" Quotient Rings
AUTHORS:
- William Stein - Simon King (2011-04): Put it into the category framework, use the new coercion model. - Simon King (2011-04): Quotients of non-commutative rings by twosided ideals.
TESTS::
sage: R.<x> = PolynomialRing(ZZ) sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) sage: S = R.quotient_ring(I);
.. todo::
The following skipped tests should be removed once :trac:`13999` is fixed::
sage: TestSuite(S).run(skip=['_test_nonzero_equal', '_test_elements', '_test_zero'])
In :trac:`11068`, non-commutative quotient rings `R/I` were implemented. The only requirement is that the two-sided ideal `I` provides a ``reduce`` method so that ``I.reduce(x)`` is the normal form of an element `x` with respect to `I` (i.e., we have ``I.reduce(x) == I.reduce(y)`` if `x-y \in I`, and ``x - I.reduce(x) in I``). Here is a toy example::
sage: from sage.rings.noncommutative_ideals import Ideal_nc sage: from itertools import product sage: class PowerIdeal(Ideal_nc): ....: def __init__(self, R, n): ....: self._power = n ....: self._power = n ....: Ideal_nc.__init__(self, R, [R.prod(m) for m in product(R.gens(), repeat=n)]) ....: def reduce(self,x): ....: R = self.ring() ....: return add([c*R(m) for m,c in x if len(m)<self._power],R(0)) ....: sage: F.<x,y,z> = FreeAlgebra(QQ, 3) sage: I3 = PowerIdeal(F,3); I3 Twosided Ideal (x^3, x^2*y, x^2*z, x*y*x, x*y^2, x*y*z, x*z*x, x*z*y, x*z^2, y*x^2, y*x*y, y*x*z, y^2*x, y^3, y^2*z, y*z*x, y*z*y, y*z^2, z*x^2, z*x*y, z*x*z, z*y*x, z*y^2, z*y*z, z^2*x, z^2*y, z^3) of Free Algebra on 3 generators (x, y, z) over Rational Field
Free algebras have a custom quotient method that serves at creating finite dimensional quotients defined by multiplication matrices. We are bypassing it, so that we obtain the default quotient::
sage: Q3.<a,b,c> = F.quotient(I3) sage: Q3 Quotient of Free Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x^3, x^2*y, x^2*z, x*y*x, x*y^2, x*y*z, x*z*x, x*z*y, x*z^2, y*x^2, y*x*y, y*x*z, y^2*x, y^3, y^2*z, y*z*x, y*z*y, y*z^2, z*x^2, z*x*y, z*x*z, z*y*x, z*y^2, z*y*z, z^2*x, z^2*y, z^3) sage: (a+b+2)^4 16 + 32*a + 32*b + 24*a^2 + 24*a*b + 24*b*a + 24*b^2 sage: Q3.is_commutative() False
Even though `Q_3` is not commutative, there is commutativity for products of degree three::
sage: a*(b*c)-(b*c)*a==F.zero() True
If we quotient out all terms of degree two then of course the resulting quotient ring is commutative::
sage: I2 = PowerIdeal(F,2); I2 Twosided Ideal (x^2, x*y, x*z, y*x, y^2, y*z, z*x, z*y, z^2) of Free Algebra on 3 generators (x, y, z) over Rational Field sage: Q2.<a,b,c> = F.quotient(I2) sage: Q2.is_commutative() True sage: (a+b+2)^4 16 + 32*a + 32*b
Since :trac:`7797`, there is an implementation of free algebras based on Singular's implementation of the Letterplace Algebra. Our letterplace wrapper allows to provide the above toy example more easily::
sage: from itertools import product sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') sage: Q3 = F.quo(F*[F.prod(m) for m in product(F.gens(), repeat=3)]*F) sage: Q3 Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*x*x, x*x*y, x*x*z, x*y*x, x*y*y, x*y*z, x*z*x, x*z*y, x*z*z, y*x*x, y*x*y, y*x*z, y*y*x, y*y*y, y*y*z, y*z*x, y*z*y, y*z*z, z*x*x, z*x*y, z*x*z, z*y*x, z*y*y, z*y*z, z*z*x, z*z*y, z*z*z) sage: Q3.0*Q3.1-Q3.1*Q3.0 xbar*ybar - ybar*xbar sage: Q3.0*(Q3.1*Q3.2)-(Q3.1*Q3.2)*Q3.0 0 sage: Q2 = F.quo(F*[F.prod(m) for m in product(F.gens(), repeat=2)]*F) sage: Q2.is_commutative() True
""" #***************************************************************************** # Copyright (C) 2005 William Stein <wstein@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. # http://www.gnu.org/licenses/ #*****************************************************************************
from __future__ import absolute_import from six.moves import range
import sage.misc.latex as latex from . import ring, ideal, quotient_ring_element import sage.rings.polynomial.multi_polynomial_ideal from sage.structure.category_object import normalize_names from sage.structure.richcmp import richcmp_method, richcmp import sage.structure.parent_gens from sage.interfaces.singular import singular as singular_default, is_SingularElement from sage.misc.cachefunc import cached_method from sage.categories.rings import Rings from sage.categories.commutative_rings import CommutativeRings
def QuotientRing(R, I, names=None): r""" Creates a quotient ring of the ring `R` by the twosided ideal `I`.
Variables are labeled by ``names`` (if the quotient ring is a quotient of a polynomial ring). If ``names`` isn't given, 'bar' will be appended to the variable names in `R`.
INPUT:
- ``R`` -- a ring.
- ``I`` -- a twosided ideal of `R`.
- ``names`` -- (optional) a list of strings to be used as names for the variables in the quotient ring `R/I`.
OUTPUT: `R/I` - the quotient ring `R` mod the ideal `I`
ASSUMPTION:
``I`` has a method ``I.reduce(x)`` returning the normal form of elements `x\in R`. In other words, it is required that ``I.reduce(x)==I.reduce(y)`` `\iff x-y \in I`, and ``x-I.reduce(x) in I``, for all `x,y\in R`.
EXAMPLES:
Some simple quotient rings with the integers::
sage: R = QuotientRing(ZZ,7*ZZ); R Quotient of Integer Ring by the ideal (7) sage: R.gens() (1,) sage: 1*R(3); 6*R(3); 7*R(3) 3 4 0
::
sage: S = QuotientRing(ZZ,ZZ.ideal(8)); S Quotient of Integer Ring by the ideal (8) sage: 2*S(4) 0
With polynomial rings (note that the variable name of the quotient ring can be specified as shown below)::
sage: P.<x> = QQ[] sage: R.<xx> = QuotientRing(P, P.ideal(x^2 + 1)) sage: R Univariate Quotient Polynomial Ring in xx over Rational Field with modulus x^2 + 1 sage: R.gens(); R.gen() (xx,) xx sage: for n in range(4): xx^n 1 xx -1 -xx
::
sage: P.<x> = QQ[] sage: S = QuotientRing(P, P.ideal(x^2 - 2)) sage: S Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 - 2 sage: xbar = S.gen(); S.gen() xbar sage: for n in range(3): xbar^n 1 xbar 2
Sage coerces objects into ideals when possible::
sage: P.<x> = QQ[] sage: R = QuotientRing(P, x^2 + 1); R Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 + 1
By Noether's homomorphism theorems, the quotient of a quotient ring of `R` is just the quotient of `R` by the sum of the ideals. In this example, we end up modding out the ideal `(x)` from the ring `\QQ[x,y]`::
sage: R.<x,y> = PolynomialRing(QQ,2) sage: S.<a,b> = QuotientRing(R,R.ideal(1 + y^2)) sage: T.<c,d> = QuotientRing(S,S.ideal(a)) sage: T Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x, y^2 + 1) sage: R.gens(); S.gens(); T.gens() (x, y) (a, b) (0, d) sage: for n in range(4): d^n 1 d -1 -d
TESTS:
By :trac:`11068`, the following does not return a generic quotient ring but a usual quotient of the integer ring::
sage: R = Integers(8) sage: I = R.ideal(2) sage: R.quotient(I) Ring of integers modulo 2
Here is an example of the quotient of a free algebra by a twosided homogeneous ideal (see :trac:`7797`)::
sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F sage: Q.<a,b,c> = F.quo(I); Q Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) sage: a*b -b*c sage: a^3 -b*c*a - b*c*b - b*c*c sage: J = Q*[a^3-b^3]*Q sage: R.<i,j,k> = Q.quo(J); R Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (-y*y*z - y*z*x - 2*y*z*z, x*y + y*z, x*x + x*y - y*x - y*y) sage: i^3 -j*k*i - j*k*j - j*k*k sage: j^3 -j*k*i - j*k*j - j*k*k
Check that :trac:`5978` is fixed by if we quotient by the zero ideal `(0)` then we just return ``R``::
sage: R = QQ['x'] sage: R.quotient(R.zero_ideal()) Univariate Polynomial Ring in x over Rational Field sage: R.<x> = PolynomialRing(ZZ) sage: R is R.quotient(R.zero_ideal()) True sage: I = R.ideal(0) sage: R is R.quotient(I) True """ # 1. Not all rings inherit from the base class of rings. # 2. We want to support quotients of free algebras by homogeneous two-sided ideals. #if not isinstance(R, commutative_ring.CommutativeRing): # raise TypeError, "R must be a commutative ring." raise TypeError("R must be a ring.") except (AttributeError, NotImplementedError): is_commutative = False else: raise AttributeError except AttributeError: raise TypeError("A twosided ideal is required.")
def is_QuotientRing(x): """ Tests whether or not ``x`` inherits from :class:`QuotientRing_nc`.
EXAMPLES::
sage: from sage.rings.quotient_ring import is_QuotientRing sage: R.<x> = PolynomialRing(ZZ,'x') sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) sage: S = R.quotient_ring(I) sage: is_QuotientRing(S) True sage: is_QuotientRing(R) False
::
sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F sage: Q = F.quo(I) sage: is_QuotientRing(Q) True sage: is_QuotientRing(F) False
"""
from sage.categories.rings import Rings _Rings = Rings() _RingsQuotients = Rings().Quotients() from sage.categories.commutative_rings import CommutativeRings _CommutativeRingsQuotients = CommutativeRings().Quotients() from sage.structure.category_object import check_default_category
@richcmp_method class QuotientRing_nc(ring.Ring, sage.structure.parent_gens.ParentWithGens): """ The quotient ring of `R` by a twosided ideal `I`.
This class is for rings that do not inherit from :class:`~sage.rings.ring.CommutativeRing`.
EXAMPLES:
Here is a quotient of a free algebra by a twosided homogeneous ideal::
sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F sage: Q.<a,b,c> = F.quo(I); Q Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) sage: a*b -b*c sage: a^3 -b*c*a - b*c*b - b*c*c
A quotient of a quotient is just the quotient of the original top ring by the sum of two ideals::
sage: J = Q*[a^3-b^3]*Q sage: R.<i,j,k> = Q.quo(J); R Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (-y*y*z - y*z*x - 2*y*z*z, x*y + y*z, x*x + x*y - y*x - y*y) sage: i^3 -j*k*i - j*k*j - j*k*k sage: j^3 -j*k*i - j*k*j - j*k*k
For rings that *do* inherit from :class:`~sage.rings.ring.CommutativeRing`, we provide a subclass :class:`QuotientRing_generic`, for backwards compatibility.
EXAMPLES::
sage: R.<x> = PolynomialRing(ZZ,'x') sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) sage: S = R.quotient_ring(I); S Quotient of Univariate Polynomial Ring in x over Integer Ring by the ideal (x^2 + 3*x + 4, x^2 + 1)
::
sage: R.<x,y> = PolynomialRing(QQ) sage: S.<a,b> = R.quo(x^2 + y^2) sage: a^2 + b^2 == 0 True sage: S(0) == a^2 + b^2 True
Again, a quotient of a quotient is just the quotient of the original top ring by the sum of two ideals.
::
sage: R.<x,y> = PolynomialRing(QQ,2) sage: S.<a,b> = R.quo(1 + y^2) sage: T.<c,d> = S.quo(a) sage: T Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x, y^2 + 1) sage: T.gens() (0, d) """ Element = quotient_ring_element.QuotientRingElement def __init__(self, R, I, names, category=None): """ Create the quotient ring of `R` by the twosided ideal `I`.
INPUT:
- ``R`` -- a ring.
- ``I`` -- a twosided ideal of `R`.
- ``names`` -- a list of generator names.
EXAMPLES::
sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F sage: Q.<a,b,c> = F.quo(I); Q Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) sage: a*b -b*c sage: a^3 -b*c*a - b*c*b - b*c*c
""" raise TypeError("The first argument must be a ring, but %s is not"%R) raise TypeError("The second argument must be an ideal of the given ring, but %s is not"%I) #sage.structure.parent_gens.ParentWithGens.__init__(self, R.base_ring(), names) ## # Unfortunately, computing the join of categories, which is done in # check_default_category, is very expensive. # However, we don't just want to use the given category without mixing in # some quotient stuff - unless Parent.__init__ was called # previously, in which case the quotient ring stuff is just # a vaste of time. This is the case for FiniteField_prime_modn. except (AttributeError, NotImplementedError): commutative = False category = check_default_category(_CommutativeRingsQuotients,category) else: # self._populate_coercion_lists_([R]) # we don't want to do this, since subclasses will often implement improved coercion maps.
def construction(self): """ Returns the functorial construction of ``self``.
EXAMPLES::
sage: R.<x> = PolynomialRing(ZZ,'x') sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) sage: R.quotient_ring(I).construction() (QuotientFunctor, Univariate Polynomial Ring in x over Integer Ring) sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F sage: Q = F.quo(I) sage: Q.construction() (QuotientFunctor, Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field)
TESTS::
sage: F, R = Integers(5).construction() sage: F(R) Ring of integers modulo 5 sage: F, R = GF(5).construction() sage: F(R) Finite Field of size 5 """ # Is there a better generic way to distinguish between things like Z/pZ as a field and Z/pZ as a ring? except ValueError: try: names = self.cover_ring().variable_names() except ValueError: names = None
def _repr_(self): """ Return a string representation of ``self``.
EXAMPLES::
sage: R.<x> = PolynomialRing(ZZ,'x') sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) sage: R.quotient_ring(I)._repr_() 'Quotient of Univariate Polynomial Ring in x over Integer Ring by the ideal (x^2 + 3*x + 4, x^2 + 1)' """
def _latex_(self): """ Return a latex representation of ``self``.
EXAMPLES::
sage: R.<x> = PolynomialRing(ZZ,'x') sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) sage: R.quotient_ring(I)._latex_() '\\Bold{Z}[x]/\\left(x^{2} + 3x + 4, x^{2} + 1\\right)\\Bold{Z}[x]' """
def is_commutative(self): """ Tell whether this quotient ring is commutative.
.. NOTE::
This is certainly the case if the cover ring is commutative. Otherwise, if this ring has a finite number of generators, it is tested whether they commute. If the number of generators is infinite, a ``NotImplementedError`` is raised.
AUTHOR:
- Simon King (2011-03-23): See :trac:`7797`.
EXAMPLES:
Any quotient of a commutative ring is commutative::
sage: P.<a,b,c> = QQ[] sage: P.quo(P.random_element()).is_commutative() True
The non-commutative case is more interesting::
sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F sage: Q = F.quo(I) sage: Q.is_commutative() False sage: Q.1*Q.2==Q.2*Q.1 False
In the next example, the generators apparently commute::
sage: J = F*[x*y-y*x,x*z-z*x,y*z-z*y,x^3-y^3]*F sage: R = F.quo(J) sage: R.is_commutative() True
""" except (AttributeError, NotImplementedError): pass raise NotImplementedError("This quotient ring has an infinite number of generators.")
@cached_method def cover(self): r""" The covering ring homomorphism `R \to R/I`, equipped with a section.
EXAMPLES::
sage: R = ZZ.quo(3*ZZ) sage: pi = R.cover() sage: pi Ring morphism: From: Integer Ring To: Ring of integers modulo 3 Defn: Natural quotient map sage: pi(5) 2 sage: l = pi.lift()
::
sage: R.<x,y> = PolynomialRing(QQ) sage: Q = R.quo( (x^2,y^2) ) sage: pi = Q.cover() sage: pi(x^3+y) ybar sage: l = pi.lift(x+y^3) sage: l x sage: l = pi.lift(); l Set-theoretic ring morphism: From: Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2, y^2) To: Multivariate Polynomial Ring in x, y over Rational Field Defn: Choice of lifting map sage: l(x+y^3) x """
@cached_method def lifting_map(self): """ Return the lifting map to the cover.
EXAMPLES::
sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S = R.quotient(x^2 + y^2) sage: pi = S.cover(); pi Ring morphism: From: Multivariate Polynomial Ring in x, y over Rational Field To: Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) Defn: Natural quotient map sage: L = S.lifting_map(); L Set-theoretic ring morphism: From: Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) To: Multivariate Polynomial Ring in x, y over Rational Field Defn: Choice of lifting map sage: L(S.0) x sage: L(S.1) y
Note that some reduction may be applied so that the lift of a reduction need not equal the original element::
sage: z = pi(x^3 + 2*y^2); z -xbar*ybar^2 + 2*ybar^2 sage: L(z) -x*y^2 + 2*y^2 sage: L(z) == x^3 + 2*y^2 False
Test that there also is a lift for rings that are no instances of :class:`~sage.rings.ring.Ring` (see :trac:`11068`)::
sage: MS = MatrixSpace(GF(5),2,2) sage: I = MS*[MS.0*MS.1,MS.2+MS.3]*MS sage: Q = MS.quo(I) sage: Q.lift() Set-theoretic ring morphism: From: Quotient of Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 5 by the ideal ( [0 1] [0 0], <BLANKLINE> [0 0] [1 1] ) <BLANKLINE> To: Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 5 Defn: Choice of lifting map
"""
# The following is to make the category framework happy. def lift(self,x=None): """ Return the lifting map to the cover, or the image of an element under the lifting map.
.. NOTE::
The category framework imposes that ``Q.lift(x)`` returns the image of an element `x` under the lifting map. For backwards compatibility, we let ``Q.lift()`` return the lifting map.
EXAMPLES::
sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S = R.quotient(x^2 + y^2) sage: S.lift() Set-theoretic ring morphism: From: Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) To: Multivariate Polynomial Ring in x, y over Rational Field Defn: Choice of lifting map sage: S.lift(S.0) == x True
"""
def retract(self,x): """ The image of an element of the cover ring under the quotient map.
INPUT:
- ``x`` -- An element of the cover ring
OUTPUT:
The image of the given element in ``self``.
EXAMPLES::
sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S = R.quotient(x^2 + y^2) sage: S.retract((x+y)^2) 2*xbar*ybar
"""
def characteristic(self): r""" Return the characteristic of the quotient ring.
.. TODO::
Not yet implemented!
EXAMPLES::
sage: Q = QuotientRing(ZZ,7*ZZ) sage: Q.characteristic() Traceback (most recent call last): ... NotImplementedError """
def defining_ideal(self): r""" Returns the ideal generating this quotient ring.
EXAMPLES:
In the integers::
sage: Q = QuotientRing(ZZ,7*ZZ) sage: Q.defining_ideal() Principal ideal (7) of Integer Ring
An example involving a quotient of a quotient. By Noether's homomorphism theorems, this is actually a quotient by a sum of two ideals::
sage: R.<x,y> = PolynomialRing(QQ,2) sage: S.<a,b> = QuotientRing(R,R.ideal(1 + y^2)) sage: T.<c,d> = QuotientRing(S,S.ideal(a)) sage: S.defining_ideal() Ideal (y^2 + 1) of Multivariate Polynomial Ring in x, y over Rational Field sage: T.defining_ideal() Ideal (x, y^2 + 1) of Multivariate Polynomial Ring in x, y over Rational Field """
@cached_method def is_field(self, proof = True): r""" Returns ``True`` if the quotient ring is a field. Checks to see if the defining ideal is maximal.
TESTS::
sage: Q = QuotientRing(ZZ,7*ZZ) sage: Q.is_field() True
Requires the ``is_maximal`` method of the defining ideal to be implemented::
sage: R.<x, y> = ZZ[] sage: R.quotient_ring(R.ideal([2, 4 +x])).is_field() Traceback (most recent call last): ... NotImplementedError """ else:
@cached_method def is_integral_domain(self, proof=True): r""" With ``proof`` equal to ``True`` (the default), this function may raise a ``NotImplementedError``.
When ``proof`` is ``False``, if ``True`` is returned, then self is definitely an integral domain. If the function returns ``False``, then either ``self`` is not an integral domain or it was unable to determine whether or not ``self`` is an integral domain.
EXAMPLES::
sage: R.<x,y> = QQ[] sage: R.quo(x^2 - y).is_integral_domain() True sage: R.quo(x^2 - y^2).is_integral_domain() False sage: R.quo(x^2 - y^2).is_integral_domain(proof=False) False sage: R.<a,b,c> = ZZ[] sage: Q = R.quotient_ring([a, b]) sage: Q.is_integral_domain() Traceback (most recent call last): ... NotImplementedError sage: Q.is_integral_domain(proof=False) False """ else:
def is_noetherian(self): r""" Return ``True`` if this ring is Noetherian.
EXAMPLES::
sage: R = QuotientRing(ZZ, 102*ZZ) sage: R.is_noetherian() True
sage: P.<x> = QQ[] sage: R = QuotientRing(P, x^2+1) sage: R.is_noetherian() True
If the cover ring of ``self`` is not Noetherian, we currently have no way of testing whether ``self`` is Noetherian, so we raise an error::
sage: R.<x> = InfinitePolynomialRing(QQ) sage: R.is_noetherian() False sage: I = R.ideal([x[1]^2, x[2]]) sage: S = R.quotient(I) sage: S.is_noetherian() Traceback (most recent call last): ... NotImplementedError """ # Naive test: if this is the quotient of a Noetherian ring, # then it is Noetherian. Otherwise we give up.
def cover_ring(self): r""" Returns the cover ring of the quotient ring: that is, the original ring `R` from which we modded out an ideal, `I`.
EXAMPLES::
sage: Q = QuotientRing(ZZ,7*ZZ) sage: Q.cover_ring() Integer Ring
::
sage: P.<x> = QQ[] sage: Q = QuotientRing(P, x^2 + 1) sage: Q.cover_ring() Univariate Polynomial Ring in x over Rational Field """
# This is to make the category framework happy ambient = cover_ring
def ideal(self, *gens, **kwds): """ Return the ideal of ``self`` with the given generators.
EXAMPLES::
sage: R.<x,y> = PolynomialRing(QQ) sage: S = R.quotient_ring(x^2+y^2) sage: S.ideal() Ideal (0) of Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) sage: S.ideal(x+y+1) Ideal (xbar + ybar + 1) of Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2)
TESTS:
We create an ideal of a fairly generic integer ring (see :trac:`5666`)::
sage: R = Integers(10) sage: R.ideal(1) Principal ideal (1) of Ring of integers modulo 10 """ (not hasattr(self.__R, '_has_singular') or not self.__R._has_singular): # pass through gens = list(gens) coerce = True gens = [self(x) for x in gens] # this will even coerce from singular ideals correctly!
def _element_constructor_(self, x, coerce=True): """ Construct an element with ``self`` as the parent.
EXAMPLES::
sage: R.<x,y> = PolynomialRing(QQ) sage: S = R.quotient_ring(x^2+y^2) sage: S(x) # indirect doctest xbar sage: S(x^2 + y^2) 0
The rings that coerce into the quotient ring canonically, are:
- this ring
- anything that coerces into the ring of which this is the quotient
::
sage: R.<x,y> = PolynomialRing(QQ, 2) sage: S.<a,b> = R.quotient(x^2 + y^2) sage: S.coerce(0) 0 sage: S.coerce(2/3) 2/3 sage: S.coerce(a^2 - b) -b^2 - b sage: S.coerce(GF(7)(3)) Traceback (most recent call last): ... TypeError: no canonical coercion from Finite Field of size 7 to Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) """ return x #self._singular_().set_ring()
def _coerce_map_from_(self, R): """ Return ``True`` if there is a coercion map from ``R`` to ``self``.
EXAMPLES::
sage: R.<x,y> = PolynomialRing(QQ) sage: S = R.quotient_ring(x^2+y^2) sage: S.has_coerce_map_from(R) # indirect doctest True sage: S.has_coerce_map_from(QQ) True sage: T = S.quotient_ring(x^3 - y) sage: S.has_coerce_map_from(T) False sage: T.has_coerce_map_from(R) True
TESTS:
We check that :trac:`13682` is fixed::
sage: R.<x,y> = PolynomialRing(QQ) sage: I = R.ideal(x^2+y^2) sage: J = R.ideal(x^2+y^2, x^3 - y) sage: I < J True sage: S = R.quotient(I) sage: T = R.quotient(J) sage: T.has_coerce_map_from(S) True sage: S.quotient_ring(x^4-x*y+1).has_coerce_map_from(S) True sage: S.has_coerce_map_from(T) False
We also allow coercions with the cover rings::
sage: Rp.<x,y> = PolynomialRing(ZZ) sage: Ip = Rp.ideal(x^2+y^2) sage: Jp = Rp.ideal(x^2+y^2, x^3 - y) sage: Sp = Rp.quotient(Ip) sage: Tp = Rp.quotient(Jp) sage: R.has_coerce_map_from(Rp) True sage: Sp.has_coerce_map_from(Sp) True sage: T.has_coerce_map_from(Sp) True sage: Sp.has_coerce_map_from(T) False """
def __richcmp__(self, other, op): r""" Only quotients by the *same* ring and same ideal (with the same generators!!) are considered equal.
EXAMPLES::
sage: R.<x,y> = PolynomialRing(QQ) sage: S = R.quotient_ring(x^2 + y^2) sage: S == R.quotient_ring(x^2 + y^2) True
The ideals `(x^2 + y^2)` and `(-x^2-y^2)` are equal, but since the generators are different, the corresponding quotient rings are not equal::
sage: R.ideal(x^2+y^2) == R.ideal(-x^2 - y^2) True sage: R.quotient_ring(x^2 + y^2) == R.quotient_ring(-x^2 - y^2) False """ (other.cover_ring(), other.defining_ideal().gens()), op)
def ngens(self): r""" Returns the number of generators for this quotient ring.
.. TODO::
Note that ``ngens`` counts 0 as a generator. Does this make sense? That is, since 0 only generates itself and the fact that this is true for all rings, is there a way to "knock it off" of the generators list if a generator of some original ring is modded out?
EXAMPLES::
sage: R = QuotientRing(ZZ,7*ZZ) sage: R.gens(); R.ngens() (1,) 1
::
sage: R.<x,y> = PolynomialRing(QQ,2) sage: S.<a,b> = QuotientRing(R,R.ideal(1 + y^2)) sage: T.<c,d> = QuotientRing(S,S.ideal(a)) sage: T Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x, y^2 + 1) sage: R.gens(); S.gens(); T.gens() (x, y) (a, b) (0, d) sage: R.ngens(); S.ngens(); T.ngens() 2 2 2 """
def gen(self, i=0): r""" Returns the `i`-th generator for this quotient ring.
EXAMPLES::
sage: R = QuotientRing(ZZ,7*ZZ) sage: R.gen(0) 1
::
sage: R.<x,y> = PolynomialRing(QQ,2) sage: S.<a,b> = QuotientRing(R,R.ideal(1 + y^2)) sage: T.<c,d> = QuotientRing(S,S.ideal(a)) sage: T Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x, y^2 + 1) sage: R.gen(0); R.gen(1) x y sage: S.gen(0); S.gen(1) a b sage: T.gen(0); T.gen(1) 0 d """
def _singular_(self, singular=singular_default): """ Returns the Singular quotient ring of ``self`` if the base ring is coercible to Singular.
If a valid Singular representation is found it is used otherwise a new 'qring' is created.
INPUT:
- ``singular`` - Singular instance (default: the default Singular instance)
.. NOTE::
This method also sets the current ring in Singular to ``self``
EXAMPLES::
sage: R.<x,y> = PolynomialRing(QQ) sage: S = R.quotient_ring(x^2+y^2) sage: S._singular_() polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 2 // block 1 : ordering dp // : names x y // block 2 : ordering C // quotient ring from ideal _[1]=x2+y2 """ raise ValueError
def _singular_init_(self,singular=singular_default): """ Returns a newly created Singular quotient ring matching ``self`` if the base ring is coercible to Singular.
See ``_singular_``
EXAMPLES::
sage: R.<x,y> = PolynomialRing(QQ) sage: S = R.quotient_ring(x^2+y^2) sage: T = S._singular_init_() sage: parent(S) <class 'sage.rings.quotient_ring.QuotientRing_generic_with_category'> sage: parent(T) Singular """
def _magma_init_(self, magma): r""" Return string that evaluates to Magma version of this quotient ring. This is called implicitly when doing conversions to Magma.
INPUT:
- ``magma`` - a Magma instance
EXAMPLES::
sage: P.<x,y> = PolynomialRing(GF(2)) sage: Q = P.quotient(sage.rings.ideal.FieldIdeal(P)) sage: magma(Q) # optional - magma # indirect doctest Affine Algebra of rank 2 over GF(2) Graded Reverse Lexicographical Order Variables: x, y Quotient relations: [ x^2 + x, y^2 + y ] """ R = magma(self.__R) I = magma(self.__I.gens()) return "quo<%s|%s>"%(R.name(), I._ref())
def term_order(self): """ Return the term order of this ring.
EXAMPLES::
sage: P.<a,b,c> = PolynomialRing(QQ) sage: I = Ideal([a^2 - a, b^2 - b, c^2 - c]) sage: Q = P.quotient(I) sage: Q.term_order() Degree reverse lexicographic term order """
class QuotientRing_generic(QuotientRing_nc, ring.CommutativeRing): r""" Creates a quotient ring of a *commutative* ring `R` by the ideal `I`.
EXAMPLES::
sage: R.<x> = PolynomialRing(ZZ) sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) sage: S = R.quotient_ring(I); S Quotient of Univariate Polynomial Ring in x over Integer Ring by the ideal (x^2 + 3*x + 4, x^2 + 1) """
def __init__(self, R, I, names, category=None): """ Initialize ``self``.
INPUT:
- ``R`` -- a ring that is a :class:`~sage.rings.ring.CommutativeRing`.
- ``I`` -- an ideal of `R`.
- ``names`` -- a list of generator names.
TESTS::
sage: isinstance(ZZ.quo(2), sage.rings.ring.CommutativeRing) # indirect doctest True """ raise TypeError("This class is for quotients of commutative rings only.\n For non-commutative rings, use <sage.rings.quotient_ring.QuotientRing_nc>") |