# -*- coding: utf-8 -*-
"""
Quotients of Univariate Polynomial Rings

EXAMPLES::

    sage: R.<x> = QQ[]
    sage: S = R.quotient(x**3-3*x+1, 'alpha')
    sage: S.gen()**2 in S
    True
    sage: x in S
    True
    sage: S.gen() in R
    False
    sage: 1 in S
    True

TESTS::

    sage: Pol.<y> = CBF[]
    sage: Quo.<y> = Pol.quotient(y^3)
    sage: CBF.zero()*y
    0
    sage: ((x - 1)/(x + 1))(1 + y)
    -0.2500000000000000*y^2 + 0.5000000000000000*y
"""

#*****************************************************************************
#       Copyright (C) 2005, 2006 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, print_function
from six.moves import range

import six
import sage.rings.number_field.all
from . import polynomial_element
import sage.rings.rational_field
import sage.rings.complex_field

from sage.rings.ring import Field, IntegralDomain, CommutativeRing

from sage.misc.cachefunc import cached_method
from sage.rings.polynomial.polynomial_quotient_ring_element import PolynomialQuotientRingElement
from sage.rings.polynomial.polynomial_ring import PolynomialRing_commutative

from sage.categories.commutative_algebras import CommutativeAlgebras

from sage.structure.category_object import normalize_names

from sage.rings.polynomial.infinite_polynomial_ring import GenDictWithBasering
from sage.all import sage_eval, parent


def PolynomialQuotientRing(ring, polynomial, names=None):
    r"""
    Create a quotient of a polynomial ring.

    INPUT:


    -  ``ring`` - a univariate polynomial ring in one
       variable.

    -  ``polynomial`` - element with unit leading coefficient

    -  ``names`` - (optional) name for the variable


    OUTPUT: Creates the quotient ring R/I, where R is the ring and I is
    the principal ideal generated by the polynomial.

    EXAMPLES:

    We create the quotient ring `\ZZ[x]/(x^3+7)`, and
    demonstrate many basic functions with it::

        sage: Z = IntegerRing()
        sage: R = PolynomialRing(Z,'x'); x = R.gen()
        sage: S = R.quotient(x^3 + 7, 'a'); a = S.gen()
        sage: S
        Univariate Quotient Polynomial Ring in a over Integer Ring with modulus x^3 + 7
        sage: a^3
        -7
        sage: S.is_field()
        False
        sage: a in S
        True
        sage: x in S
        True
        sage: a in R
        False
        sage: S.polynomial_ring()
        Univariate Polynomial Ring in x over Integer Ring
        sage: S.modulus()
        x^3 + 7
        sage: S.degree()
        3

    We create the "iterated" polynomial ring quotient

    .. MATH::

                    R = (\GF{2}[y]/(y^{2}+y+1))[x]/(x^3 - 5).



    ::

        sage: A.<y> = PolynomialRing(GF(2)); A
        Univariate Polynomial Ring in y over Finite Field of size 2 (using NTL)
        sage: B = A.quotient(y^2 + y + 1, 'y2'); B
        Univariate Quotient Polynomial Ring in y2 over Finite Field of size 2 with modulus y^2 + y + 1
        sage: C = PolynomialRing(B, 'x'); x=C.gen(); C
        Univariate Polynomial Ring in x over Univariate Quotient Polynomial Ring in y2 over Finite Field of size 2 with modulus y^2 + y + 1
        sage: R = C.quotient(x^3 - 5); R
        Univariate Quotient Polynomial Ring in xbar over Univariate Quotient Polynomial Ring in y2 over Finite Field of size 2 with modulus y^2 + y + 1 with modulus x^3 + 1

    Next we create a number field, but viewed as a quotient of a
    polynomial ring over `\QQ`::

        sage: R = PolynomialRing(RationalField(), 'x'); x = R.gen()
        sage: S = R.quotient(x^3 + 2*x - 5, 'a')
        sage: S
        Univariate Quotient Polynomial Ring in a over Rational Field with modulus x^3 + 2*x - 5
        sage: S.is_field()
        True
        sage: S.degree()
        3

    There are conversion functions for easily going back and forth
    between quotients of polynomial rings over `\QQ` and
    number fields::

        sage: K = S.number_field(); K
        Number Field in a with defining polynomial x^3 + 2*x - 5
        sage: K.polynomial_quotient_ring()
        Univariate Quotient Polynomial Ring in a over Rational Field with modulus x^3 + 2*x - 5

    The leading coefficient must be a unit (but need not be 1).

    ::

        sage: R = PolynomialRing(Integers(9), 'x'); x = R.gen()
        sage: S = R.quotient(2*x^4 + 2*x^3 + x + 2, 'a')
        sage: S = R.quotient(3*x^4 + 2*x^3 + x + 2, 'a')
        Traceback (most recent call last):
        ...
        TypeError: polynomial must have unit leading coefficient

    Another example::

        sage: R.<x> = PolynomialRing(IntegerRing())
        sage: f = x^2 + 1
        sage: R.quotient(f)
        Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 + 1

    This shows that the issue at :trac:`5482` is solved::

        sage: R.<x> = PolynomialRing(QQ)
        sage: f = x^2-1
        sage: R.quotient_by_principal_ideal(f)
        Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 - 1
    """
    if not isinstance(ring, PolynomialRing_commutative):
        raise TypeError("ring must be a polynomial ring")
    if not isinstance(polynomial, polynomial_element.Polynomial):
        raise TypeError("must be a polynomial")
    if not polynomial.parent() == ring:
        raise TypeError("polynomial must be in ring")
    c = polynomial.leading_coefficient()
    if not c.is_unit():
        raise TypeError("polynomial must have unit leading coefficient")
    if names is None:
        names = tuple([x + 'bar' for x in ring.variable_names()])
    else:
        names = normalize_names(ring.ngens(), names)
    R = ring.base_ring()
    if isinstance(R, IntegralDomain):
        try:
            if polynomial.is_irreducible():
                if isinstance(R, Field):
                    return PolynomialQuotientRing_field(ring, polynomial, names)
                else:
                    return PolynomialQuotientRing_domain(ring, polynomial, names)
        except NotImplementedError:   # is_irreducible sometimes not implemented
            pass
    return PolynomialQuotientRing_generic(ring, polynomial, names)


def is_PolynomialQuotientRing(x):
    return isinstance(x, PolynomialQuotientRing_generic)


class PolynomialQuotientRing_generic(CommutativeRing):
    """
    Quotient of a univariate polynomial ring by an ideal.

    EXAMPLES::

        sage: R.<x> = PolynomialRing(Integers(8)); R
        Univariate Polynomial Ring in x over Ring of integers modulo 8
        sage: S.<xbar> = R.quotient(x^2 + 1); S
        Univariate Quotient Polynomial Ring in xbar over Ring of integers modulo 8 with modulus x^2 + 1

    We demonstrate object persistence.

    ::

        sage: loads(S.dumps()) == S
        True
        sage: loads(xbar.dumps()) == xbar
        True

    We create some sample homomorphisms;

    ::

        sage: R.<x> = PolynomialRing(ZZ)
        sage: S = R.quo(x^2-4)
        sage: f = S.hom([2])
        sage: f
        Ring morphism:
          From: Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 - 4
          To:   Integer Ring
          Defn: xbar |--> 2
        sage: f(x)
        2
        sage: f(x^2 - 4)
        0
        sage: f(x^2)
        4

    TESTS:

    By trac ticket :trac:`11900`, polynomial quotient rings use Sage's
    category framework. They do so in an unusual way: During their
    initialisation, they are declared to be objects in the category of
    quotients of commutative algebras over a base ring. However, if it
    is tested whether a quotient ring is actually a field, the
    category might be refined, which also includes a change of the
    class of the quotient ring and its newly created elements.

    Thus, in order to document that this works fine, we go into some detail::

        sage: P.<x> = QQ[]
        sage: Q = P.quotient(x^2+2)
        sage: Q.category()
        Category of commutative no zero divisors
        quotients of algebras over Rational Field

    The test suite passes::

        sage: TestSuite(Q).run()

    We verify that the elements belong to the correct element class.
    Also, we list the attributes that are provided by the element
    class of the category, and store the current class of the quotient
    ring::

        sage: isinstance(Q.an_element(),Q.element_class)
        True
        sage: [s for s in dir(Q.category().element_class) if not s.startswith('_')]
        ['cartesian_product', 'inverse_of_unit', 'is_idempotent', 'is_one', 'is_unit', 'lift', 'powers']
        sage: first_class = Q.__class__

    We try to find out whether `Q` is a field. Indeed it is, and thus its category,
    including its class and element class, is changed accordingly::

        sage: Q in Fields()
        True
        sage: Q.category()
        Category of commutative division no zero divisors
        quotients of algebras over Rational Field
        sage: first_class == Q.__class__
        False
        sage: [s for s in dir(Q.category().element_class) if not s.startswith('_')]
        ['cartesian_product',
         'euclidean_degree',
         'factor',
         'gcd',
         'inverse_of_unit',
         'is_idempotent',
         'is_one',
         'is_unit',
         'lcm',
         'lift',
         'powers',
         'quo_rem',
         'xgcd']

    As one can see, the elements are now inheriting additional
    methods: lcm and gcd. Even though ``Q.an_element()`` belongs to
    the old and not to the new element class, it still inherits the
    new methods from the category of fields, thanks to
    :meth:`Element.__getattr__`::

        sage: e = Q.an_element()
        sage: isinstance(e, Q.element_class)
        False
        sage: e.gcd(e+1)
        1

    Since the category has changed, we repeat the test suite. However, we have to skip the test
    for its elements, since `an_element` has been cached in the previous run of the test suite,
    and we have already seen that its class is not matching the new element class::

        sage: TestSuite(Q).run(skip=['_test_elements'])

    Newly created elements are fine, though, and their test suite passes::

        sage: TestSuite(Q(x)).run()
        sage: isinstance(Q(x), Q.element_class)
        True
    """
    Element = PolynomialQuotientRingElement

    def __init__(self, ring, polynomial, name=None, category=None):
        """
        TESTS::

            sage: R.<x> = PolynomialRing(ZZ)
            sage: S = R.quo(x^2-4)
            sage: from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic
            sage: S == PolynomialQuotientRing_generic(R,x^2-4,'xbar')
            True

        """
        if not isinstance(ring, PolynomialRing_commutative):
            raise TypeError("R must be a univariate polynomial ring.")

        if not isinstance(polynomial, polynomial_element.Polynomial):
            raise TypeError("f must be a Polynomial")

        if polynomial.parent() != ring:
            raise TypeError("f must have parent R")

        self.__ring = ring
        self.__polynomial = polynomial
        category = CommutativeAlgebras(ring.base_ring()).Quotients().or_subcategory(category)
        CommutativeRing.__init__(self, ring, names=name, category=category)

    def __reduce__(self):
        """
        TEST:

        Note the polynomial quotient rings are not unique parent structures::

            sage: P.<x> = QQ[]
            sage: R.<y> = P[]
            sage: Q = R.quo([(y^2+1)])
            sage: Q is loads(dumps(Q))
            False
            sage: Q == loads(dumps(Q))
            True
        """
        return PolynomialQuotientRing_generic, (self.__ring, self.__polynomial, self.variable_names())

    def _element_constructor_(self, x):
        """
        Convert x into this quotient ring. Anything that can be converted into
        the polynomial ring can be converted into the quotient.

        INPUT:


        -  ``x`` - object to be converted


        OUTPUT: an element obtained by converting x into this ring.

        EXAMPLES::

            sage: R.<x> = PolynomialRing(QQ)
            sage: S.<alpha> = R.quotient(x^3-3*x+1)
            sage: S(x)
            alpha
            sage: S(x^3)
            3*alpha - 1
            sage: S([1,2])
            2*alpha + 1
            sage: S([1,2,3,4,5])
            18*alpha^2 + 9*alpha - 3
            sage: S(S.gen()+1)
            alpha + 1
            sage: S(S.gen()^10+1)
            90*alpha^2 - 109*alpha + 28

        TESTS:

        Conversion should work even if there is no coercion.
        This was fixed in :trac:`8800`::

            sage: P.<x> = QQ[]
            sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)])
            sage: Q = P.quo([(x^2+1)^2])
            sage: Q1.has_coerce_map_from(Q)
            False
            sage: Q1(Q.gen())
            xbar

        Here we test against several issues discussed in :trac:`8992`::

            sage: P.<x> = QQ[]
            sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)])
            sage: Q2 = P.quo([(x^2+1)^2*(x^5+3)])
            sage: p = Q1.gen() + Q2.gen()
            sage: p
            2*xbar
            sage: p.parent()
            Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^4 + 2*x^2 + 1
            sage: p.parent()('xbar')
            xbar

        Note that the result of string conversion has the correct parent, even
        when the given string suggests an element of the cover ring or the base
        ring::

            sage: a = Q1('x'); a
            xbar
            sage: a.parent() is Q1
            True
            sage: b = Q1('1'); b
            1
            sage: b.parent() is Q1
            True

        Conversion may lift an element of one quotient ring to the base ring of
        another quotient ring::

            sage: R.<y> = P[]
            sage: Q3 = R.quo([(y^2+1)])
            sage: Q3(Q1.gen())
            x
            sage: Q3.has_coerce_map_from(Q1)
            False

        String conversion takes into account both the generators of the quotient
        ring and its base ring::

            sage: Q3('x*ybar^2')
            -x

        """
        P = parent(x)
        if P is self:
            return x
        if not isinstance(x, six.string_types):
            try:
                return self.element_class(self, self.__ring(x) , check=True)
            except TypeError:
                xlift = getattr(x,'lift',None)
                if xlift is not None: # duck typing for quotient ring elements
                    return self.element_class(self, self.__ring(x.lift()), check=False)
        # The problem with the string representation is that it could in principle
        # mix elements of self with elements of self's cover ring. We therefore
        # resort to sage_eval.
        # Interpretation in self has priority over interpretation in self.__ring
        try:
            out = sage_eval(x, GenDictWithBasering(self,self.gens_dict()))
            if out.parent() is not self:
                return self(out)
            return out
        except (TypeError, NameError):
            pass
        try:
            return self.element_class(self, self.__ring(x), check=False)
        except TypeError:
            raise TypeError("unable to convert %r to an element of %s"%(x, self))

    def _coerce_map_from_(self, R):
        """
        Anything coercing into ``self``'s polynomial ring coerces into ``self``.
        Any quotient polynomial ring whose polynomial ring coerces into
        ``self``'s polynomial ring and whose modulus is divided by the modulus
        of ``self`` coerces into ``self``. There is no coercion if the division
        of the moduli fails.

        AUTHOR:

        - Simon King (2010-12): :trac:`8800`

        TESTS::

            sage: P5.<x> = GF(5)[]
            sage: Q = P5.quo([(x^2+1)^2])
            sage: P.<x> = ZZ[]
            sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)])
            sage: Q2 = P.quo([(x^2+1)^2*(x^5+3)])
            sage: Q.has_coerce_map_from(Q1)  #indirect doctest
            True
            sage: Q1.has_coerce_map_from(Q)
            False
            sage: Q1.has_coerce_map_from(Q2)
            False

        The following tests against a bug fixed in :trac:`8992`::

            sage: P.<x> = QQ[]
            sage: Q1 = P.quo([(x^2+1)^2*(x^2-3)])
            sage: R.<y> = P[]
            sage: Q2 = R.quo([(y^2+1)])
            sage: Q2.has_coerce_map_from(Q1)
            False

        """
        if self.__ring.has_coerce_map_from(R):
            return True
        if isinstance(R, PolynomialQuotientRing_generic):
            try:
                if not self.__polynomial.divides(R.modulus()):
                    return False
            except (ZeroDivisionError,ArithmeticError):
                return False
            return self.__ring.has_coerce_map_from(R.polynomial_ring())

    def _is_valid_homomorphism_(self, codomain, im_gens):
        try:
            # We need that elements of the base ring of the polynomial
            # ring map canonically into codomain.

            codomain._coerce_(self.base_ring()(1))

            # We also need that the polynomial modulus maps to 0.
            f = self.modulus()
            return codomain(f(im_gens[0])) == 0
        except (TypeError, ValueError):
            return False

    def _coerce_impl(self, x):
        """
        Return the coercion of x into this polynomial quotient ring.

        The rings that coerce into the quotient ring canonically are:

        - this ring

        - any canonically isomorphic ring

        - anything that coerces into the ring of which this is the
          quotient
        """
        if isinstance(x, PolynomialQuotientRingElement):
            if x.parent() == self:
                return self.element_class(self, self.__ring(x.lift()), check=False)
        # any ring that coerces to the base ring of this polynomial ring.
        return self._coerce_try(x, [self.polynomial_ring()])

    ############################################
    ## Methods to make the category framework happy...
    ##

    retract = _coerce_impl
    ambient = CommutativeRing.base

    def lift(self, x):
        """
        Return an element of the ambient ring mapping to the given argument.

        EXAMPLES::

            sage: P.<x> = QQ[]
            sage: Q = P.quotient(x^2+2)
            sage: Q.lift(Q.0^3)
            -2*x
            sage: Q(-2*x)
            -2*xbar
            sage: Q.0^3
            -2*xbar

        """
        return x.lift()

    def __cmp__(self, other):
        """
        Compare self and other.

        EXAMPLES::

            sage: Rx.<x> = PolynomialRing(QQ)
            sage: Ry.<y> = PolynomialRing(QQ)
            sage: Rx == Ry
            False
            sage: Qx = Rx.quotient(x^2+1)
            sage: Qy = Ry.quotient(y^2+1)
            sage: Qx == Qy
            False
            sage: Qx == Qx
            True
            sage: Qz = Rx.quotient(x^2+1)
            sage: Qz == Qx
            True
        """
        if not isinstance(other, PolynomialQuotientRing_generic):
            return cmp(type(self), type(other))
        c = cmp(self.polynomial_ring(), other.polynomial_ring())
        if c: return c
        return cmp(self.modulus(), other.modulus())

    def _singular_init_(self, S=None):
        """
        Represent ``self`` in the Singular interface.

        TESTS::

            sage: P.<x> = QQ[]
            sage: Q = P.quo([(x^2+1)])
            sage: singular(Q)        # indirect doctest
            polynomial ring, over a field, global ordering
            //   coefficients: QQ
            //   number of vars : 1
            //        block   1 : ordering lp
            //                  : names    xbar
            //        block   2 : ordering C
            // quotient ring from ideal
            _[1]=xbar^2+1
            sage: singular(Q.gen())
            xbar

        """
        if S is None:
            from sage.all import singular
            S = singular
        Rpoly = S(self.polynomial_ring())
        Rpoly.set_ring()
        modulus = S(self.modulus()) # should live in Rpoly
        Rtmp = S(self.polynomial_ring().change_var(self.variable_name()))
        Rtmp.set_ring()
        self.__singular = S("ideal(fetch(%s,%s))"%(Rpoly.name(),modulus.name()),"qring")
        return self.__singular


    def _repr_(self):
        return "Univariate Quotient Polynomial Ring in %s over %s with modulus %s"%(
            self.variable_name(), self.base_ring(), self.modulus())

    def construction(self):
        """
        Functorial construction of ``self``

        EXAMPLES::

            sage: P.<t>=ZZ[]
            sage: Q = P.quo(5+t^2)
            sage: F, R = Q.construction()
            sage: F(R) == Q
            True
            sage: P.<t> = GF(3)[]
            sage: Q = P.quo([2+t^2])
            sage: F, R = Q.construction()
            sage: F(R) == Q
            True

        AUTHOR:

        -- Simon King (2010-05)
        """
        from sage.categories.pushout import QuotientFunctor
        return QuotientFunctor([self.modulus()]*self.base(),self.variable_names()), self.base()

    @cached_method
    def base_ring(self):
        r"""
        Return the base ring of the polynomial ring, of which this ring is
        a quotient.

        EXAMPLES:

        The base ring of
        `\ZZ[z]/(z^3 + z^2 + z + 1)` is
        `\ZZ`.

        ::

            sage: R.<z> = PolynomialRing(ZZ)
            sage: S.<beta> = R.quo(z^3 + z^2 + z + 1)
            sage: S.base_ring()
            Integer Ring

        Next we make a polynomial quotient ring over `S` and ask
        for its base ring.

        ::

            sage: T.<t> = PolynomialRing(S)
            sage: W = T.quotient(t^99 + 99)
            sage: W.base_ring()
            Univariate Quotient Polynomial Ring in beta over Integer Ring with modulus z^3 + z^2 + z + 1
        """
        return self.__ring.base_ring()

    def cardinality(self):
        """
        Return the number of elements of this quotient ring.

        EXAMPLES::

            sage: R.<x> = ZZ[]
            sage: R.quo(1).cardinality()
            1
            sage: R.quo(x^3-2).cardinality()
            +Infinity

        ::

            sage: R.<x> = GF(9,'a')[]
            sage: R.quo(2*x^3+x+1).cardinality()
            729
            sage: GF(9,'a').extension(2*x^3+x+1).cardinality()
            729
            sage: R.quo(2).cardinality()
            1
        """
        if not self.is_finite():
            from sage.rings.infinity import Infinity
            return Infinity
        f = self.modulus()
        # Two cases where the quotient is finite (see is_finite())
        # 1) R[x]/(1)
        if f.degree() == 0:
            return 1
        # 2) F[x]/(f) where F is finite
        return self.base_ring().cardinality() ** f.degree()

    def characteristic(self):
        """
        Return the characteristic of this quotient ring.

        This is always the same as the characteristic of the base ring.

        EXAMPLES::

            sage: R.<z> = PolynomialRing(ZZ)
            sage: S.<a> = R.quo(z - 19)
            sage: S.characteristic()
            0
            sage: R.<x> = PolynomialRing(GF(9,'a'))
            sage: S = R.quotient(x^3 + 1)
            sage: S.characteristic()
            3
        """
        return self.base_ring().characteristic()

    def degree(self):
        """
        Return the degree of this quotient ring. The degree is the degree
        of the polynomial that we quotiented out by.

        EXAMPLES::

            sage: R.<x> = PolynomialRing(GF(3))
            sage: S = R.quotient(x^2005 + 1)
            sage: S.degree()
            2005
        """
        return self.modulus().degree()

    def discriminant(self, v=None):
        """
        Return the discriminant of this ring over the base ring. This is by
        definition the discriminant of the polynomial that we quotiented
        out by.

        EXAMPLES::

            sage: R.<x> = PolynomialRing(QQ)
            sage: S = R.quotient(x^3 + x^2 + x + 1)
            sage: S.discriminant()
            -16
            sage: S = R.quotient((x + 1) * (x + 1))
            sage: S.discriminant()
            0

        The discriminant of the quotient polynomial ring need not equal the
        discriminant of the corresponding number field, since the
        discriminant of a number field is by definition the discriminant of
        the ring of integers of the number field::

            sage: S = R.quotient(x^2 - 8)
            sage: S.number_field().discriminant()
            8
            sage: S.discriminant()
            32
        """
        return self.modulus().discriminant()

    def gen(self, n=0):
        """
        Return the generator of this quotient ring. This is the equivalence
        class of the image of the generator of the polynomial ring.

        EXAMPLES::

            sage: R.<x> = PolynomialRing(QQ)
            sage: S = R.quotient(x^2 - 8, 'gamma')
            sage: S.gen()
            gamma
        """
        if n != 0:
            raise IndexError("Only one generator.")
        try:
            return self.__gen
        except AttributeError:
            self.__gen = self(self.polynomial_ring().gen())
            return self.__gen

    def is_field(self, proof = True):
        """
        Return whether or not this quotient ring is a field.

        EXAMPLES::

            sage: R.<z> = PolynomialRing(ZZ)
            sage: S = R.quo(z^2-2)
            sage: S.is_field()
            False
            sage: R.<x> = PolynomialRing(QQ)
            sage: S = R.quotient(x^2 - 2)
            sage: S.is_field()
            True

        If proof is ``True``, requires the ``is_irreducible`` method of the
        modulus to be implemented::

            sage: R1.<x> = GF(5)[]
            sage: F1 = R1.quotient_ring(x^2+x+1)
            sage: R2.<x> = F1[]
            sage: F2 = R2.quotient_ring(x^2+x+1)
            sage: F2.is_field()
            Traceback (most recent call last):
            ...
            NotImplementedError
            sage: F2.is_field(proof = False)
            False
        """
        if proof:
            return self.base_ring().is_field(True) and self.modulus().is_irreducible()
        try:
            return self.base_ring().is_field(False) and self.modulus().is_irreducible()
        except NotImplementedError:
            return False

    def krull_dimension(self):
        return self.base_ring().krull_dimension()

    def modulus(self):
        """
        Return the polynomial modulus of this quotient ring.

        EXAMPLES::

            sage: R.<x> = PolynomialRing(GF(3))
            sage: S = R.quotient(x^2 - 2)
            sage: S.modulus()
            x^2 + 1
        """
        return self.__polynomial

    def ngens(self):
        """
        Return the number of generators of this quotient ring over the base
        ring. This function always returns 1.

        EXAMPLES::

            sage: R.<x> = PolynomialRing(QQ)
            sage: S.<y> = PolynomialRing(R)
            sage: T.<z> = S.quotient(y + x)
            sage: T
            Univariate Quotient Polynomial Ring in z over Univariate Polynomial Ring in x over Rational Field with modulus y + x
            sage: T.ngens()
            1
        """
        return 1

    def number_field(self):
        """
        Return the number field isomorphic to this quotient polynomial
        ring, if possible.

        EXAMPLES::

            sage: R.<x> = PolynomialRing(QQ)
            sage: S.<alpha> = R.quotient(x^29 - 17*x - 1)
            sage: K = S.number_field()
            sage: K
            Number Field in alpha with defining polynomial x^29 - 17*x - 1
            sage: alpha = K.gen()
            sage: alpha^29
            17*alpha + 1
        """
        if self.characteristic() != 0:
            raise ArithmeticError("Polynomial quotient ring is not isomorphic to a number field (it has positive characteristic).")

        if not isinstance(self.base_ring(), sage.rings.rational_field.RationalField):
            raise NotImplementedError("Computation of number field only implemented for quotients of the polynomial ring over the rational field.")
        return sage.rings.number_field.all.NumberField(self.modulus(), self.variable_name())

    def order(self):
        """
        Return the number of elements of this quotient ring.

        EXAMPLES::

            sage: F1.<a> = GF(2^7)
            sage: P1.<x> = F1[]
            sage: F2 = F1.extension(x^2+x+1, 'u')
            sage: F2.order()
            16384

            sage: F1 = QQ
            sage: P1.<x> = F1[]
            sage: F2 = F1.extension(x^2+x+1, 'u')
            sage: F2.order()
            +Infinity
        """
        return self.base_ring().order() ** self.degree()

    def polynomial_ring(self):
        """
        Return the polynomial ring of which this ring is the quotient.

        EXAMPLES::

            sage: R.<x> = PolynomialRing(QQ)
            sage: S = R.quotient(x^2-2)
            sage: S.polynomial_ring()
            Univariate Polynomial Ring in x over Rational Field
        """
        return self.__ring

    cover_ring = polynomial_ring

    def random_element(self, *args, **kwds):
        """
        Return a random element of this quotient ring.

        INPUT:

        - ``*args``, ``**kwds`` - Arguments for randomization that are passed
          on to the ``random_element`` method of the polynomial ring, and from
          there to the base ring

        OUTPUT:

        - Element of this quotient ring

        EXAMPLES::

            sage: F1.<a> = GF(2^7)
            sage: P1.<x> = F1[]
            sage: F2 = F1.extension(x^2+x+1, 'u')
            sage: F2.random_element()
            (a^6 + 1)*u + a^5 + a^4 + a^3 + 1
        """
        return self(self.polynomial_ring().random_element( \
            degree=self.degree()-1, *args, **kwds))

    @cached_method
    def _S_decomposition(self, S):
        """
        Compute the decomposition of self into a product of number fields.

        This is an internal function used by
        :meth:`S_class_group`, :meth:`S_units` and :meth:`selmer_group`.

        EXAMPLES::

            sage: K.<a> = QuadraticField(-5)
            sage: R.<x> = K[]
            sage: S.<xbar> = R.quotient((x^2 + 23)*(x^2 + 31))
            sage: fields, isos, iso_classes = S._S_decomposition(tuple(K.primes_above(3)))

        Representatives of the number fields up to isomorphism that
        occur in the decomposition::

            sage: fields
            [Number Field in x0 with defining polynomial x^2 + 23 over its base field,
             Number Field in x1 with defining polynomial x^2 + 31 over its base field]

        In this case, the isomorphisms of these representatives to the components
        are the identity maps::

            sage: isos
            [(Ring endomorphism of Number Field in y0 with defining polynomial x^4 + 56*x^2 + 324
              Defn: y0 |--> y0,
              0),
             (Ring endomorphism of Number Field in y1 with defining polynomial x^4 + 72*x^2 + 676
              Defn: y1 |--> y1,
              1)]

        There are four primes above 3 in the first component and two
        in the second component::

            sage: len(iso_classes[0][1])
            4
            sage: len(iso_classes[1][1])
            2
        """
        from sage.rings.number_field.number_field_base import is_NumberField
        K = self.base_ring()
        if not is_NumberField(K) or not self.__polynomial.is_squarefree():
            raise NotImplementedError

        from sage.rings.ideal import is_Ideal
        for p in S:
            # second check due to inconsistency over QQ - see # 7596
            if not (is_Ideal(p)
                    and (p.ring() is K or p.ring() is K.ring_of_integers())
                    and p.is_prime()):
                raise TypeError("S must be a list of prime ideals of the base field.")

        F = self.__polynomial.factor()
        fields = []
        isos = []
        iso_classes = []
        i = 0
        for f, _ in F:
            D = K.extension(f, 'x'+str(i))
            fields.append(D)
            D_abs = D.absolute_field('y'+str(i))
            i += 1

            seen_before = False
            j = 0
            for D_iso,_ in iso_classes:
                if D_abs.is_isomorphic(D_iso):
                    seen_before = True; break
                j += 1
            if not seen_before:
                S_abs = []
                for p in S:
                    abs_gens = []
                    for g in D.ideal(p.gens()).gens(): # this line looks a bit silly, due to inconsistency over QQ - see # 7596
                        abs_gens.append(D_abs.structure()[1](g))
                    S_abs += [pp for pp,_ in D_abs.ideal(abs_gens).factor()]
                iso_classes.append((D_abs,S_abs))
            isos.append((D_abs.embeddings(D_abs)[0], j))
        return fields, isos, iso_classes

    def S_class_group(self, S, proof=True):
        r"""
        If self is an étale algebra `D` over a number field `K` (i.e.
        a quotient of `K[x]` by a squarefree polynomial) and `S` is a
        finite set of places of `K`, return a list of generators of
        the `S`-class group of `D`.

        NOTE:

        Since the ``ideal`` function behaves differently over number
        fields than over polynomial quotient rings (the quotient does
        not even know its ring of integers), we return a set of pairs
        ``(gen, order)``, where ``gen`` is a tuple of generators of an
        ideal `I` and ``order`` is the order of `I` in the `S`-class
        group.

        INPUT:

        - ``S`` - a set of primes of the coefficient ring

        - ``proof`` - if False, assume the GRH in computing the class group

        OUTPUT:

        A list of generators of the `S`-class group, in the form
        ``(gen, order)``, where ``gen`` is a tuple of elements
        generating a fractional ideal `I` and ``order`` is the order
        of `I` in the `S`-class group.

        EXAMPLES:

        A trivial algebra over `\QQ(\sqrt{-5})` has the same class group as its
        base::

            sage: K.<a> = QuadraticField(-5)
            sage: R.<x> = K[]
            sage: S.<xbar> = R.quotient(x)
            sage: S.S_class_group([])
            [((2, -a + 1), 2)]

        When we include the prime `(2, -a+1)`, the `S`-class group
        becomes trivial::

            sage: S.S_class_group([K.ideal(2, -a+1)])
            []

        Here is an example where the base and the extension both contribute to
        the class group::

            sage: K.<a> = QuadraticField(-5)
            sage: K.class_group()
            Class group of order 2 with structure C2 of Number Field in a with defining polynomial x^2 + 5
            sage: R.<x> = K[]
            sage: S.<xbar> = R.quotient(x^2 + 23)
            sage: S.S_class_group([])
            [((2, -a + 1, 1/2*xbar + 1/2, -1/2*a*xbar + 1/2*a + 1), 6)]
            sage: S.S_class_group([K.ideal(3, a-1)])
            []
            sage: S.S_class_group([K.ideal(2, a+1)])
            []
            sage: S.S_class_group([K.ideal(a)])
            [((2, -a + 1, 1/2*xbar + 1/2, -1/2*a*xbar + 1/2*a + 1), 6)]

        Now we take an example over a nontrivial base with two factors, each
        contributing to the class group::

            sage: K.<a> = QuadraticField(-5)
            sage: R.<x> = K[]
            sage: S.<xbar> = R.quotient((x^2 + 23)*(x^2 + 31))
            sage: S.S_class_group([])
            [((1/4*xbar^2 + 31/4,
               (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8,
               1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16,
               -1/16*a*xbar^3 + (1/16*a + 1/8)*xbar^2 - 31/16*a*xbar + 31/16*a + 31/8),
              6),
             ((-1/4*xbar^2 - 23/4,
               (1/8*a - 1/8)*xbar^2 + 23/8*a - 23/8,
               -1/16*xbar^3 - 1/16*xbar^2 - 23/16*xbar - 23/16,
               1/16*a*xbar^3 + (-1/16*a - 1/8)*xbar^2 + 23/16*a*xbar - 23/16*a - 23/8),
              6),
             ((-5/4*xbar^2 - 115/4,
               1/4*a*xbar^2 + 23/4*a,
               -1/16*xbar^3 - 7/16*xbar^2 - 23/16*xbar - 161/16,
               1/16*a*xbar^3 - 1/16*a*xbar^2 + 23/16*a*xbar - 23/16*a),
              2)]

        By using the ideal `(a)`, we cut the part of the class group coming from
        `x^2 + 31` from 12 to 2, i.e. we lose a generator of order 6 (this was
        fixed in :trac:`14489`)::

            sage: S.S_class_group([K.ideal(a)])
            [((1/4*xbar^2 + 31/4, (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8, 1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16, -1/16*a*xbar^3 + (1/16*a + 1/8)*xbar^2 - 31/16*a*xbar + 31/16*a + 31/8), 6), ((-1/4*xbar^2 - 23/4, (1/8*a - 1/8)*xbar^2 + 23/8*a - 23/8, -1/16*xbar^3 - 1/16*xbar^2 - 23/16*xbar - 23/16, 1/16*a*xbar^3 + (-1/16*a - 1/8)*xbar^2 + 23/16*a*xbar - 23/16*a - 23/8), 2)]

        Note that all the returned values live where we expect them to::

            sage: CG = S.S_class_group([])
            sage: type(CG[0][0][1])
            <class 'sage.rings.polynomial.polynomial_quotient_ring.PolynomialQuotientRing_generic_with_category.element_class'>
            sage: type(CG[0][1])
            <type 'sage.rings.integer.Integer'>

        """
        fields, isos, iso_classes = self._S_decomposition(tuple(S))
        n = len(fields)

        component_S_class_groups = []
        for D_iso, S_iso in iso_classes:
            # compute S-class group for each distinct component
            clgp_gens = D_iso._S_class_group_and_units(tuple(S_iso), proof=proof)[1]
            component_S_class_groups.append(clgp_gens)

        clgp_gens = []
        clgp_gens_orders = []
        moduli = [D.relative_polynomial() for D in fields]
        for i in range(n):
            phi = isos[i][0]
            back_to_rel = phi.codomain().structure()[0]

            for clgp_gen, gen_order in component_S_class_groups[isos[i][1]]:
                ideal_gens = []
                for ideal_gen in clgp_gen.gens():
                    rel_ideal_gen = back_to_rel(phi(ideal_gen))
                    prod_ideal_gen = [0]*i + [rel_ideal_gen.lift()] + [0]*(n - i - 1)
                    poly_ideal_gen = self(sage.arith.all.crt(prod_ideal_gen, moduli))
                    ideal_gens.append(poly_ideal_gen)
                clgp_gens.append((tuple(ideal_gens), gen_order))

        return clgp_gens

    def class_group(self, proof=True):
        """
        If self is a quotient ring of a polynomial ring over a number
        field `K`, by a polynomial of nonzero discriminant, return a
        list of generators of the class group.

        NOTE:

        Since the ``ideal`` function behaves differently over number
        fields than over polynomial quotient rings (the quotient does
        not even know its ring of integers), we return a set of pairs
        ``(gen, order)``, where ``gen`` is a tuple of generators of an
        ideal `I` and ``order`` is the order of `I` in the class group.

        INPUT:

        - ``proof`` - if False, assume the GRH in computing the class group

        OUTPUT:

        A list of pairs ``(gen, order)``, where ``gen`` is a tuple of
        elements generating a fractional ideal and ``order`` is
        the order of `I` in the class group.

        EXAMPLES::

            sage: K.<a> = QuadraticField(-3)
            sage: K.class_group()
            Class group of order 1 of Number Field in a with defining polynomial x^2 + 3
            sage: K.<a> = QQ['x'].quotient(x^2 + 3)
            sage: K.class_group()
            []

        A trivial algebra over `\QQ(\sqrt{-5})` has the same class group as its
        base::

            sage: K.<a> = QuadraticField(-5)
            sage: R.<x> = K[]
            sage: S.<xbar> = R.quotient(x)
            sage: S.class_group()
            [((2, -a + 1), 2)]

        The same algebra constructed in a different way::

            sage: K.<a> = QQ['x'].quotient(x^2 + 5)
            sage: K.class_group(())
            [((2, a + 1), 2)]

        Here is an example where the base and the extension both contribute to
        the class group::

            sage: K.<a> = QuadraticField(-5)
            sage: K.class_group()
            Class group of order 2 with structure C2 of Number Field in a with defining polynomial x^2 + 5
            sage: R.<x> = K[]
            sage: S.<xbar> = R.quotient(x^2 + 23)
            sage: S.class_group()
            [((2, -a + 1, 1/2*xbar + 1/2, -1/2*a*xbar + 1/2*a + 1), 6)]

        Here is an example of a product of number fields, both of which
        contribute to the class group::

            sage: R.<x> = QQ[]
            sage: S.<xbar> = R.quotient((x^2 + 23)*(x^2 + 47))
            sage: S.class_group()
            [((1/12*xbar^2 + 47/12, 1/48*xbar^3 - 1/48*xbar^2 + 47/48*xbar - 47/48), 3), ((-1/12*xbar^2 - 23/12, -1/48*xbar^3 - 1/48*xbar^2 - 23/48*xbar - 23/48), 5)]

        Now we take an example over a nontrivial base with two factors, each
        contributing to the class group::

            sage: K.<a> = QuadraticField(-5)
            sage: R.<x> = K[]
            sage: S.<xbar> = R.quotient((x^2 + 23)*(x^2 + 31))
            sage: S.class_group()
            [((1/4*xbar^2 + 31/4,
               (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8,
               1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16,
               -1/16*a*xbar^3 + (1/16*a + 1/8)*xbar^2 - 31/16*a*xbar + 31/16*a + 31/8),
              6),
             ((-1/4*xbar^2 - 23/4,
               (1/8*a - 1/8)*xbar^2 + 23/8*a - 23/8,
               -1/16*xbar^3 - 1/16*xbar^2 - 23/16*xbar - 23/16,
               1/16*a*xbar^3 + (-1/16*a - 1/8)*xbar^2 + 23/16*a*xbar - 23/16*a - 23/8),
              6),
             ((-5/4*xbar^2 - 115/4,
               1/4*a*xbar^2 + 23/4*a,
               -1/16*xbar^3 - 7/16*xbar^2 - 23/16*xbar - 161/16,
               1/16*a*xbar^3 - 1/16*a*xbar^2 + 23/16*a*xbar - 23/16*a),
              2)]

        Note that all the returned values live where we expect them to::

            sage: CG = S.class_group()
            sage: type(CG[0][0][1])
            <class 'sage.rings.polynomial.polynomial_quotient_ring.PolynomialQuotientRing_generic_with_category.element_class'>
            sage: type(CG[0][1])
            <type 'sage.rings.integer.Integer'>

        """
        return self.S_class_group((), proof=proof)

    def S_units(self, S, proof=True):
        """
        If self is an étale algebra `D` over a number field `K` (i.e.
        a quotient of `K[x]` by a squarefree polynomial) and `S` is a
        finite set of places of `K`, return a list of generators of
        the group of `S`-units of `D`.

        INPUT:

        - ``S`` - a set of primes of the base field

        - ``proof`` - if False, assume the GRH in computing the class group

        OUTPUT:

        A list of generators of the `S`-unit group, in the form
        ``(gen, order)``, where ``gen`` is a unit of order ``order``.

        EXAMPLES::

            sage: K.<a> = QuadraticField(-3)
            sage: K.unit_group()
            Unit group with structure C6 of Number Field in a with defining polynomial x^2 + 3
            sage: K.<a> = QQ['x'].quotient(x^2 + 3)
            sage: u,o = K.S_units([])[0]; u, o
            (1/2*a + 1/2, 6)
            sage: u^6
            1
            sage: u^3
            -1
            sage: u^2
            1/2*a - 1/2

        ::

            sage: K.<a> = QuadraticField(-3)
            sage: y = polygen(K)
            sage: L.<b> = K['y'].quotient(y^3 + 5); L
            Univariate Quotient Polynomial Ring in b over Number Field in a with defining polynomial x^2 + 3 with modulus y^3 + 5
            sage: L.S_units([])
            [(1/2*a + 1/2, 6),
             ((-1/3*a - 1)*b^2 - 4/3*a*b - 5/6*a + 7/2, +Infinity),
             (2/3*a*b^2 + (2/3*a - 2)*b - 5/6*a - 7/2, +Infinity)]
            sage: L.S_units([K.ideal(1/2*a - 3/2)])
            [((-1/6*a - 1/2)*b^2 + (1/3*a - 1)*b + 4/3*a, +Infinity),
             (1/2*a + 1/2, 6),
             ((-1/3*a - 1)*b^2 - 4/3*a*b - 5/6*a + 7/2, +Infinity),
             (2/3*a*b^2 + (2/3*a - 2)*b - 5/6*a - 7/2, +Infinity)]
            sage: L.S_units([K.ideal(2)])
            [((1/2*a - 1/2)*b^2 + (a + 1)*b + 3, +Infinity),
             ((1/6*a + 1/2)*b^2 + (-1/3*a + 1)*b - 5/6*a + 1/2, +Infinity),
             ((1/6*a + 1/2)*b^2 + (-1/3*a + 1)*b - 5/6*a - 1/2, +Infinity),
             (1/2*a + 1/2, 6),
             ((-1/3*a - 1)*b^2 - 4/3*a*b - 5/6*a + 7/2, +Infinity),
             (2/3*a*b^2 + (2/3*a - 2)*b - 5/6*a - 7/2, +Infinity)]

        Note that all the returned values live where we expect them to::

            sage: U = L.S_units([])
            sage: type(U[0][0])
            <class 'sage.rings.polynomial.polynomial_quotient_ring.PolynomialQuotientRing_field_with_category.element_class'>
            sage: type(U[0][1])
            <type 'sage.rings.integer.Integer'>
            sage: type(U[1][1])
            <class 'sage.rings.infinity.PlusInfinity'>

        """
        fields, isos, iso_classes = self._S_decomposition(tuple(S))
        n = len(fields)

        component_S_units = []
        for D_iso, S_iso in iso_classes:
            # compute S-units for each distinct component
            units = D_iso.S_units(S_iso, proof=proof)
            component_S_units.append(units)

        units = []
        moduli = [D.relative_polynomial() for D in fields]
        for i in range(n):
            phi = isos[i][0]
            back_to_rel = phi.codomain().structure()[0]

            for unit in component_S_units[isos[i][1]]:
                mul_order = unit.multiplicative_order()
                rel_unit = back_to_rel(phi(unit))
                prod_unit = [1]*i + [rel_unit.lift()] + [1]*(n - i - 1)
                poly_unit = self(sage.arith.all.crt(prod_unit, moduli))
                units.append((poly_unit, mul_order))

        return units

    def units(self, proof=True):
        """
        If this quotient ring is over a number field K, by a polynomial of
        nonzero discriminant, returns a list of generators of the units.

        INPUT:

        - ``proof`` - if False, assume the GRH in computing the class group

        OUTPUT:

        A list of generators of the unit group, in the form ``(gen, order)``,
        where ``gen`` is a unit of order ``order``.

        EXAMPLES::

            sage: K.<a> = QuadraticField(-3)
            sage: K.unit_group()
            Unit group with structure C6 of Number Field in a with defining polynomial x^2 + 3
            sage: K.<a> = QQ['x'].quotient(x^2 + 3)
            sage: u = K.units()[0][0]; u
            1/2*a + 1/2
            sage: u^6
            1
            sage: u^3
            -1
            sage: u^2
            1/2*a - 1/2
            sage: K.<a> = QQ['x'].quotient(x^2 + 5)
            sage: K.units(())
            [(-1, 2)]

        ::

            sage: K.<a> = QuadraticField(-3)
            sage: y = polygen(K)
            sage: L.<b> = K['y'].quotient(y^3 + 5); L
            Univariate Quotient Polynomial Ring in b over Number Field in a with defining polynomial x^2 + 3 with modulus y^3 + 5
            sage: L.units()
            [(1/2*a + 1/2, 6),
             ((-1/3*a - 1)*b^2 - 4/3*a*b - 5/6*a + 7/2, +Infinity),
             (2/3*a*b^2 + (2/3*a - 2)*b - 5/6*a - 7/2, +Infinity)]
            sage: L.<b> = K.extension(y^3 + 5)
            sage: L.unit_group()
            Unit group with structure C6 x Z x Z of Number Field in b with defining polynomial x^3 + 5 over its base field
            sage: L.unit_group().gens()    # abstract generators
            (u0, u1, u2)
            sage: L.unit_group().gens_values()
            [1/2*a + 1/2, (-1/3*a - 1)*b^2 - 4/3*a*b - 5/6*a + 7/2, 2/3*a*b^2 + (2/3*a - 2)*b - 5/6*a - 7/2]

        Note that all the returned values live where we expect them to::

            sage: L.<b> = K['y'].quotient(y^3 + 5)
            sage: U = L.units()
            sage: type(U[0][0])
            <class 'sage.rings.polynomial.polynomial_quotient_ring.PolynomialQuotientRing_field_with_category.element_class'>
            sage: type(U[0][1])
            <type 'sage.rings.integer.Integer'>
            sage: type(U[1][1])
            <class 'sage.rings.infinity.PlusInfinity'>

        """
        return self.S_units((), proof=proof)

    def selmer_group(self, S, m, proof=True):
        r"""
        If self is an étale algebra `D` over a number field `K` (i.e.
        a quotient of `K[x]` by a squarefree polynomial) and `S` is a
        finite set of places of `K`, compute the Selmer group
        `D(S,m)`.  This is the subgroup of `D^*/(D^*)^m` consisting of
        elements `a` such that `D(\sqrt[m]{a})/D` is unramified at all
        primes of `D` lying above a place outside of `S`.

        INPUT:

        - ``S`` - A set of primes of the coefficient ring (which is a number field).

        - ``m`` - a positive integer

        - ``proof`` - if False, assume the GRH in computing the class group

        OUTPUT:

        A list of generators of `D(S,m)`.

        EXAMPLES::

            sage: K.<a> = QuadraticField(-5)
            sage: R.<x> = K[]
            sage: D.<T> = R.quotient(x)
            sage: D.selmer_group((), 2)
            [-1, 2]
            sage: D.selmer_group([K.ideal(2, -a+1)], 2)
            [2, -1]
            sage: D.selmer_group([K.ideal(2, -a+1), K.ideal(3, a+1)], 2)
            [2, a + 1, -1]
            sage: D.selmer_group((K.ideal(2, -a+1),K.ideal(3, a+1)), 4)
            [2, a + 1, -1]
            sage: D.selmer_group([K.ideal(2, -a+1)], 3)
            [2]
            sage: D.selmer_group([K.ideal(2, -a+1), K.ideal(3, a+1)], 3)
            [2, a + 1]
            sage: D.selmer_group([K.ideal(2, -a+1), K.ideal(3, a+1), K.ideal(a)], 3)
            [2, a + 1, a]

        """
        fields, isos, iso_classes = self._S_decomposition(tuple(S))
        n = len(fields)

        component_selmer_groups = []
        for D_iso, S_iso in iso_classes:
            sel = D_iso.selmer_group(S_iso, m, proof=proof)
            component_selmer_groups.append(sel)

        gens = []
        moduli = [D.relative_polynomial() for D in fields]
        for i in range(n):
            phi = isos[i][0]
            back_to_rel = phi.codomain().structure()[0]

            for gen in component_selmer_groups[isos[i][1]]:
                rel_gen = back_to_rel(phi(gen))
                prod_gen = [1]*i + [rel_gen.lift()] + [1]*(n - i - 1)
                poly_gen = self(sage.arith.all.crt(prod_gen, moduli))
                gens.append(poly_gen)

        return gens

class PolynomialQuotientRing_domain(PolynomialQuotientRing_generic, IntegralDomain):
    """
    EXAMPLES::

        sage: R.<x> = PolynomialRing(ZZ)
        sage: S.<xbar> = R.quotient(x^2 + 1)
        sage: S
        Univariate Quotient Polynomial Ring in xbar over Integer Ring with modulus x^2 + 1
        sage: loads(S.dumps()) == S
        True
        sage: loads(xbar.dumps()) == xbar
        True
    """
    def __init__(self, ring, polynomial, name=None, category=None):
        r"""
        Initialize ``self``.

        TESTS::

            sage: R.<x> = PolynomialRing(ZZ)
            sage: S.<xbar> = R.quotient(x^2 + 1)
            sage: TestSuite(S).run()

        Check that :trac:`17450` is fixed::

            sage: S in IntegralDomains()
            True
        """
        category = CommutativeAlgebras(ring.base_ring()).Quotients().NoZeroDivisors().or_subcategory(category)
        PolynomialQuotientRing_generic.__init__(self, ring, polynomial, name, category)

    def __reduce__(self):
        return PolynomialQuotientRing_domain, (self.polynomial_ring(),
                                         self.modulus(), self.variable_names())

    def is_finite(self):
        """
        Return whether or not this quotient ring is finite.

        EXAMPLES::

            sage: R.<x> = ZZ[]
            sage: R.quo(1).is_finite()
            True
            sage: R.quo(x^3-2).is_finite()
            False

        ::

            sage: R.<x> = GF(9,'a')[]
            sage: R.quo(2*x^3+x+1).is_finite()
            True
            sage: R.quo(2).is_finite()
            True
        """
        f = self.modulus()
        if f.degree() < 0:
            return False
        if f.degree() == 0:
            if f[0].is_unit():
                return True
            else:
                # definitely infinite, since poly ring over
                # a nonzero ring.
                return False
        # when the degree is at least 1, the quotient is finite
        # if and only if the base ring is finite:  why?  If base
        # ring infinite, clearly quotient isn't in this case, since
        # quotient embeds in.  If base ring is finite, then since
        # it is a domain it is a field, so this is a field mod a poly
        # of degree at least 1, hence it is also a finite field.
        return self.base_ring().is_finite()

    def field_extension(self, names):
        r"""
        Takes a polynomial quotient ring, and returns a tuple with three
        elements: the NumberField defined by the same polynomial quotient
        ring, a homomorphism from its parent to the NumberField sending the
        generators to one another, and the inverse isomorphism.

        OUTPUT:

        -  field

        -  homomorphism from self to field

        -  homomorphism from field to self


        EXAMPLES::

            sage: R.<x> = PolynomialRing(Rationals())
            sage: S.<alpha> = R.quotient(x^3-2)
            sage: F.<b>, f, g = S.field_extension()
            sage: F
            Number Field in b with defining polynomial x^3 - 2
            sage: a = F.gen()
            sage: f(alpha)
            b
            sage: g(a)
            alpha

        Note that the parent ring must be an integral domain::

            sage: R.<x> = GF(25,'f25')['x']
            sage: S.<a> = R.quo(x^3 - 2)
            sage: F, g, h = S.field_extension('b')
            Traceback (most recent call last):
            ...
            AttributeError: 'PolynomialQuotientRing_generic_with_category' object has no attribute 'field_extension'

        Over a finite field, the corresponding field extension is not a
        number field::

            sage: R.<x> = GF(25, 'a')['x']
            sage: S.<a> = R.quo(x^3 + 2*x + 1)
            sage: F, g, h = S.field_extension('b')
            sage: h(F.0^2 + 3)
            a^2 + 3
            sage: g(x^2 + 2)
            b^2 + 2

        We do an example involving a relative number field::

            sage: R.<x> = QQ['x']
            sage: K.<a> = NumberField(x^3 - 2)
            sage: S.<X> = K['X']
            sage: Q.<b> = S.quo(X^3 + 2*X + 1)
            sage: Q.field_extension('b')
            (Number Field in b with defining polynomial X^3 + 2*X + 1 over its base field, ...
              Defn: b |--> b, Relative number field morphism:
              From: Number Field in b with defining polynomial X^3 + 2*X + 1 over its base field
              To:   Univariate Quotient Polynomial Ring in b over Number Field in a with defining polynomial x^3 - 2 with modulus X^3 + 2*X + 1
              Defn: b |--> b
                    a |--> a)

        We slightly change the example above so it works.

        ::

            sage: R.<x> = QQ['x']
            sage: K.<a> = NumberField(x^3 - 2)
            sage: S.<X> = K['X']
            sage: f = (X+a)^3 + 2*(X+a) + 1
            sage: f
            X^3 + 3*a*X^2 + (3*a^2 + 2)*X + 2*a + 3
            sage: Q.<z> = S.quo(f)
            sage: F.<w>, g, h = Q.field_extension()
            sage: c = g(z)
            sage: f(c)
            0
            sage: h(g(z))
            z
            sage: g(h(w))
            w

        AUTHORS:

        - Craig Citro (2006-08-07)

        - William Stein (2006-08-06)
        """

        return self.gen().field_extension(names)




class PolynomialQuotientRing_field(PolynomialQuotientRing_domain, Field):
    """
    EXAMPLES::

        sage: R.<x> = PolynomialRing(QQ)
        sage: S.<xbar> = R.quotient(x^2 + 1)
        sage: S
        Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 + 1
        sage: loads(S.dumps()) == S
        True
        sage: loads(xbar.dumps()) == xbar
        True
    """
    def __init__(self, ring, polynomial, name=None):
        PolynomialQuotientRing_domain.__init__(self, ring, polynomial, name)

    def __reduce__(self):
        return PolynomialQuotientRing_field, (self.polynomial_ring(),
                                        self.modulus(), self.variable_names())

    def base_field(self):
        r"""
        Alias for base_ring, when we're defined over a field.
        """
        return self.base_ring()

    def complex_embeddings(self, prec=53):
        r"""
        Return all homomorphisms of this ring into the approximate complex
        field with precision prec.

        EXAMPLES::

            sage: R.<x> = QQ[]
            sage: f = x^5 + x + 17
            sage: k = R.quotient(f)
            sage: v = k.complex_embeddings(100)
            sage: [phi(k.0^2) for phi in v]
            [2.9757207403766761469671194565, -2.4088994371613850098316292196 + 1.9025410530350528612407363802*I, -2.4088994371613850098316292196 - 1.9025410530350528612407363802*I, 0.92103906697304693634806949137 - 3.0755331188457794473265418086*I, 0.92103906697304693634806949137 + 3.0755331188457794473265418086*I]
        """
        CC = sage.rings.complex_field.ComplexField(prec)
        v = self.modulus().roots(multiplicities=False, ring=CC)
        return [self.hom([a], check=False) for a in v]


