# sage_setup: distribution = sagemath-flint
# sage.doctest: needs sage.libs.linbox
"""
Orders in number fields

EXAMPLES:

We define an absolute order::

    sage: x = polygen(ZZ, 'x')
    sage: K.<a> = NumberField(x^2 + 1); O = K.order(2*a)
    sage: O.basis()
    [1, 2*a]

We compute a basis for an order in a relative extension
that is generated by 2 elements::

    sage: K.<a,b> = NumberField([x^2 + 1, x^2 - 3])
    sage: O = K.order([3*a, 2*b])
    sage: O.basis()
    [1, 3*a - 2*b, -6*b*a + 6, 3*a]

We compute a maximal order of a degree 10 field::

    sage: K.<a> = NumberField((x+1)^10 + 17)
    sage: K.maximal_order()
    Maximal Order generated by a in Number Field in a with defining polynomial
     x^10 + 10*x^9 + 45*x^8 + 120*x^7 + 210*x^6 + 252*x^5 + 210*x^4 + 120*x^3 + 45*x^2 + 10*x + 18

We compute a suborder, which has index a power of 17 in the maximal order::

    sage: O = K.order(17*a); O
    Order generated by 17*a in Number Field in a with defining polynomial
     x^10 + 10*x^9 + 45*x^8 + 120*x^7 + 210*x^6 + 252*x^5 + 210*x^4 + 120*x^3 + 45*x^2 + 10*x + 18
    sage: m = O.index_in(K.maximal_order()); m
    23453165165327788911665591944416226304630809183732482257
    sage: factor(m)
    17^45

AUTHORS:

- William Stein and Robert Bradshaw (2007-09): initial version
"""
# ****************************************************************************
#       Copyright (C)      2007 Robert Bradshaw <robertwb@gmail.com>
#                     2007-2009 William Stein <wstein@gmail.com>
#                     2007-2017 David Roe <roed.math@gmail.com>
#                          2008 Craig Citro <craigcitro@gmail.com>
#                          2008 Alexandru Ghitza <aghitza@alum.mit.edu>
#                          2008 Gary Furnish <bill@indirectproof.net>
#                     2008-2009 Francis Clarke <F.Clarke@Swansea.ac.uk>
#                     2008-2017 John Cremona <john.cremona@gmail.com>
#                          2008 Mike Hansen <mhansen@gmail.com>
#                     2008-2011 David Loeffler <D.Loeffler@dpmms.cam.ac.uk>
#                          2009 Sebastian Pancratz <sage@pancratz.org>
#                     2010-2016 Jeroen Demeyer <jdemeyer@cage.ugent.be>
#                          2011 Martin Albrecht <martinralbrecht@googlemail.com>
#                          2012 Vincent Delecroix <vincent.delecroix@u-bordeaux.fr>
#                     2013-2020 Marc Mezzarobba <marc@mezzarobba.net>
#                          2014 Wilfried Luebbe <wluebbe@gmail.com>
#                     2014-2016 Peter Bruin <P.J.Bruin@math.leidenuniv.nl>
#                          2014 Gonzalo Tornaría <tornaria@cmat.edu.uy>
#                     2014-2018 Frédéric Chapoton <chapoton@unistra.fr>
#                          2016 Marc Masdeu <marc.masdeu@gmail.com>
#                          2017 Édouard Rousseau <edouard.rousseau@u-psud.fr>
#                     2017-2022 Julian Rüth <julian.rueth@fsfe.org>
#                          2018 Erik M. Bray <erik.bray@lri.fr>
#                     2019-2021 Matthias Koeppe <mkoeppe@math.ucdavis.edu>
#                          2019 Tuomas Tajakka <tuomas.tajakka@gmail.com>
#                          2020 John H. Palmieri <jhpalmieri64@gmail.com>
#                          2020 Thierry Monteil <sage@lma.metelu.net>
#                          2021 Antonio Rojas <arojas@archlinux.org>
#                          2021 Jonathan Kliem <jonathan.kliem@gmail.com>
#
#  Distributed under the terms of the GNU General Public License (GPL)
#  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/
# ****************************************************************************

import sage.rings.abc
from sage.categories.integral_domains import IntegralDomains
from sage.categories.noetherian_rings import NoetherianRings
from sage.misc.cachefunc import cached_method
from sage.rings.integer_ring import ZZ
from sage.rings.monomials import monomials
from sage.rings.number_field.number_field_element import (
    OrderElement_absolute,
    OrderElement_relative,
)
from sage.rings.number_field.number_field_element_quadratic import (
    OrderElement_quadratic,
)
from sage.structure.element import Element
from sage.structure.factory import UniqueFactory
from sage.structure.parent import Parent
from sage.structure.sequence import Sequence


def quadratic_order_class_number(disc):
    r"""
    Return the class number of the quadratic order of given discriminant.

    EXAMPLES::

        sage: from sage.rings.number_field.order import quadratic_order_class_number
        sage: quadratic_order_class_number(-419)
        9
        sage: quadratic_order_class_number(60)
        2

    ALGORITHM: Either :pari:`qfbclassno` or :pari:`quadclassunit`,
    depending on the size of the discriminant.
    """
    from sage.libs.pari import pari

    # cutoffs from PARI documentation
    if disc < -10**25 or disc > 10**10:
        h = pari.quadclassunit(disc)[0]
    else:
        h = pari.qfbclassno(disc)
    return ZZ(h)


def quadratic_order_approximate_class_number(disc, *, bound=10**4):
    r"""
    Return *an approximation of* the class number of
    the quadratic order of given discriminant.

    Currently only implemented for maximal orders
    in imaginary-quadratic fields.

    EXAMPLES::

        sage: from sage.rings.number_field.order import quadratic_order_approximate_class_number
        sage: QuadraticField(-419).class_number()
        9
        sage: quadratic_order_approximate_class_number(-419)  # rel tol .01
        9.01653836091712

    ::

        sage: from sage.rings.number_field.order import quadratic_order_approximate_class_number
        sage: d = 100000000000031
        sage: QuadraticField(-d).class_number(proof=False)
        14414435
        sage: round(quadratic_order_approximate_class_number(-d))  # rel tol .01
        14407657
        sage: round(quadratic_order_approximate_class_number(-d, bound=10**6))  # rel tol .01
        14413626

    Test it against the exact class number computed for the CSIDH-512 prime (source: https://eprint.iacr.org/2019/498.pdf)::

        sage: from sage.rings.number_field.order import quadratic_order_approximate_class_number
        sage: p = 4 * prod(primes(3,374)) * 587 - 1
        sage: hreal = 84884147409828091725676728670213067387206838101828807864190286991865870575397
        sage: assert not hreal * BQFClassGroup(-p).random_element()
        sage: h = round(quadratic_order_approximate_class_number(-p, bound=10**3)); h  # rel tol .01
        85020334529027955331134025285584937708277525762952749243936367281020276898911
        sage: RR(h / hreal)  # abs tol .01
        1.00160438813790
        sage: h = round(quadratic_order_approximate_class_number(-p, bound=10**4)); h  # rel tol .01
        84396416322932187013685015858232028818143153418602750494380687212063263982976
        sage: RR(h / hreal)  # abs tol .01
        0.994254155790231
        sage: h = round(quadratic_order_approximate_class_number(-p, bound=10**5)); h  # rel tol .01
        84823787383264935642168065590216697209124465727576867303448690101681967969348
        sage: RR(h / hreal)  # abs tol .01
        0.999288912848806
        sage: h = round(quadratic_order_approximate_class_number(-p, bound=10**6)); h  # rel tol .01, long time (2s)
        84884627342209070883738394179700676127184729325091471467872632417652836154863
        sage: RR(h / hreal)  # abs tol .01, long time (2s)
        1.00000565396951

    ALGORITHM: Finite approximation of the infinite product given by
    the analytic class number formula, using primes up to ``bound``.
    """
    disc = ZZ(disc)
    if disc >= 0:
        raise NotImplementedError('only imaginary-quadratic fields supported')
    if not disc.is_fundamental_discriminant():
        raise NotImplementedError('only fundamental discriminants supported')

    from sage.rings.real_mpfr import RealField
    from sage.arith.misc import primes, kronecker_symbol
    from sage.symbolic.constants import pi

    w = 6 if disc == -3 else 4 if disc == -4 else 2
    RR = RealField(max(53, disc.bit_length()))  # wild guess!

    # compute numerator and denominator separately for speed
    L1 = L2 = RR(1)
    for ell in primes(bound):
        L1 *= ell
        L2 *= ell - kronecker_symbol(disc, ell)
    L = L1 / L2

    return RR(w * abs(disc).sqrt() * L / (2 * pi))


class OrderFactory(UniqueFactory):
    r"""
    Abstract base class for factories creating orders, such as
    :class:`AbsoluteOrderFactory` and :class:`RelativeOrderFactory`.

    TESTS::

        sage: from sage.rings.number_field.order import AbsoluteOrder, OrderFactory
        sage: isinstance(AbsoluteOrder, OrderFactory)
        True
    """

    def get_object(self, version, key, extra_args):
        r"""
        Create the order identified by ``key``.

        This overrides the default implementation to update the maximality of
        the order if it was explicitly specified.

        EXAMPLES:

        Even though orders are unique parents, this lets us update their
        internal state when they are recreated with more additional
        information available about them::

            sage: x = polygen(ZZ, 'x')
            sage: L.<a, b> = NumberField([x^2 - 1000003, x^2 - 5*1000099^2])
            sage: O = L.maximal_order([2], assume_maximal=None)

            sage: O._is_maximal_at(2)
            True
            sage: O._is_maximal_at(3) is None
            True

            sage: N = L.maximal_order([3], assume_maximal=None)
            sage: N is O
            True
            sage: N._is_maximal_at(2)
            True
            sage: N._is_maximal_at(3)
            True
        """
        is_maximal = extra_args.pop("is_maximal", None)
        is_maximal_at = extra_args.pop("is_maximal_at", {})

        order = super().get_object(version, key, extra_args)

        # Add assumptions about maximality to the order (potentially creating
        # an independent non-unique clone to support legacy use cases.)
        order = order._assume_maximal(is_maximal)
        for p, v in is_maximal_at.items():
            order = order._assume_maximal(p=p, is_maximal=v)

        return order


class AbsoluteOrderFactory(OrderFactory):
    r"""
    An order in an (absolute) number field.

    EXAMPLES::

        sage: x = polygen(ZZ, 'x')
        sage: K.<i> = NumberField(x^2 + 1)
        sage: K.order(i)
        Gaussian Integers generated by i in Number Field in i with defining polynomial x^2 + 1
    """

    def create_key_and_extra_args(self, K, module_rep, is_maximal=None, check=True, is_maximal_at=()):
        r"""
        Return normalized arguments to create an absolute order.

        TESTS:

        In particular, this normalizes the data that is used when pickling orders::

            sage: x = polygen(ZZ, 'x')
            sage: K.<i> = NumberField(x^2 + 1)
            sage: OK = K.order(i)
            sage: OK._factory_data
            (<sage.rings.number_field.order.AbsoluteOrderFactory object at 0x...>,
             (...),
             (Number Field in i with defining polynomial x^2 + 1,
              Free module of degree 2 and rank 2 over Integer Ring
              Echelon basis matrix:
              [1 0]
              [0 1]),
             {})

        Note how the above is lacking the ``is_maximal`` and ``is_maximal_at``
        keywords. These are stripped by :meth:`OrderFactory.get_object` and
        then put back in by :meth:`reduce_data`.
        """
        if check:
            if not K.is_absolute():
                raise ValueError("AbsoluteOrder must be called with an absolute number field")

            _, _, to_v = K.vector_space()
            if to_v(1) not in module_rep:
                raise ValueError("1 is not in the span of the module, hence not an order")

            if module_rep.rank() != K.degree():
                raise ValueError("the module defining an absolute order must have full rank")

        return (K, module_rep), {"is_maximal": is_maximal, "is_maximal_at": {p: True for p in is_maximal_at}}

    def create_object(self, version, key, is_maximal=None, is_maximal_at=()):
        r"""
        Create an absolute order.

        TESTS:

        This method is also used during unpickling::

            sage: x = polygen(ZZ, 'x')
            sage: K.<i> = NumberField(x^2 + 1)
            sage: OK = K.order(i)
            sage: loads(dumps(OK)) is OK
            True
        """
        K, module_rep = key

        # We intentionally ignore is_maximal and is_maximal_at.
        # OrderFactory.get_object() sets these for us.
        return Order_absolute(K, module_rep)

    def reduce_data(self, order):
        r"""
        Return the data that can be used to pickle an order created by this factory.

        This overrides the default implementation to update the latest
        knowledge about primes at which the order is maximal.

        EXAMPLES:

        This also works for relative orders since they are wrapping absolute
        orders::

            sage: x = polygen(ZZ, 'x')
            sage: L.<a, b> = NumberField([x^2 - 1000003, x^2 - 5*1000099^2])
            sage: O = L.maximal_order([5], assume_maximal=None)

            sage: s = dumps(O)
            sage: loads(s) is O
            True

            sage: N = L.maximal_order([7], assume_maximal=None)
            sage: dumps(N) == s
            False

            sage: loads(dumps(N)) is O
            True
        """
        reduction = super().reduce_data(order)
        reduction[1][3]["is_maximal"] = order._is_maximal()
        reduction[1][3]["is_maximal_at"] = order._is_maximal_at()
        return reduction


AbsoluteOrder = AbsoluteOrderFactory("sage.rings.number_field.order.AbsoluteOrder")


class RelativeOrderFactory(OrderFactory):
    r"""
    An order in a relative number field extension.

    EXAMPLES::

        sage: x = polygen(ZZ, 'x')
        sage: K.<i> = NumberField(x^2 + 1)
        sage: R.<j> = K[]
        sage: L.<j> = K.extension(j^2 - 2)
        sage: L.order([i, j])
        Relative Order generated by [-i*j + 1, -i] in
         Number Field in j with defining polynomial j^2 - 2 over its base field
    """

    def create_key_and_extra_args(self, K, absolute_order, is_maximal=None, check=True, is_maximal_at=()):
        r"""
        Return normalized arguments to create a relative order.

        TESTS:

        In particular, this normalizes the data that is used when pickling orders::

            sage: x = polygen(ZZ, 'x')
            sage: K.<i> = NumberField(x^2 + 1)
            sage: R.<j> = K[]
            sage: L.<j> = K.extension(j^2 - 2)
            sage: OK = L.order([i, j])
            sage: OK._factory_data
            (<sage.rings.number_field.order.RelativeOrderFactory object at 0x...>,
             (...),
             (Number Field in j with defining polynomial j^2 - 2 over its base field,
              Order generated by [1/2*z^2 + 1/2, 1/6*z^3 + 1/6*z] in Number Field in z with defining polynomial x^4 - 2*x^2 + 9),
             {})

        Note how the above is lacking the ``is_maximal`` and ``is_maximal_at``
        keywords. These are stripped by :meth:`OrderFactory.get_object`. Since
        they are applied to the underlying absolute order, they then get
        pickled when the underlying order is pickled.
        """
        return (K, absolute_order), {"is_maximal": is_maximal, "is_maximal_at": {p: True for p in is_maximal_at}}

    def create_object(self, version, key, is_maximal=None, is_maximal_at=()):
        r"""
        Create a relative order.

        TESTS:

        This method is also used during unpickling::

            sage: x = polygen(ZZ, 'x')
            sage: K.<i> = NumberField(x^2 + 1)
            sage: R.<j> = K[]
            sage: L.<j> = K.extension(j^2 - 2)
            sage: OK = L.order([i, j])
            sage: loads(dumps(OK)) is OK
            True
        """
        K, absolute_order = key

        # We intentionally ignore is_maximal and is_maximal_at.
        # OrderFactory.get_object() sets these for us.
        return Order_relative(K, absolute_order)


RelativeOrder = RelativeOrderFactory("sage.rings.number_field.order.RelativeOrder")


def is_NumberFieldOrder(R):
    r"""
    Return ``True`` if `R` is either an order in a number field or is the ring `\ZZ` of integers.

    EXAMPLES::

        sage: from sage.rings.number_field.order import is_NumberFieldOrder
        sage: x = polygen(ZZ, 'x')
        sage: is_NumberFieldOrder(NumberField(x^2 + 1, 'a').maximal_order())
        doctest:warning...
        DeprecationWarning: The function is_NumberFieldOrder is deprecated;
        use 'isinstance(..., sage.rings.abc.Order) or ... == ZZ' instead.
        See https://github.com/sagemath/sage/issues/38124 for details.
        True
        sage: is_NumberFieldOrder(ZZ)
        True
        sage: is_NumberFieldOrder(QQ)
        False
        sage: is_NumberFieldOrder(45)
        False
    """
    from sage.misc.superseded import deprecation
    deprecation(38124,
                "The function is_NumberFieldOrder is deprecated; "
                "use 'isinstance(..., sage.rings.abc.Order) or ... == ZZ' instead.")
    return isinstance(R, Order) or R == ZZ


def EquationOrder(f, names, **kwds):
    r"""
    Return the equation order generated by a root of the irreducible
    polynomial `f` or list ``f`` of polynomials (to construct a relative
    equation order).

    IMPORTANT: Note that the generators of the returned order need
    *not* be roots of `f`, since the generators of an order are -- in
    Sage -- module generators.

    EXAMPLES::

        sage: x = polygen(ZZ, 'x')
        sage: O.<a,b> = EquationOrder([x^2 + 1, x^2 + 2])
        sage: O
        Relative Order generated by [-b*a - 1, -3*a + 2*b] in
         Number Field in a with defining polynomial x^2 + 1 over its base field
        sage: O.0
        -b*a - 1
        sage: O.1
        -3*a + 2*b

    Of course the input polynomial must be integral::

        sage: R = EquationOrder(x^3 + x + 1/3, 'alpha'); R
        Traceback (most recent call last):
        ...
        ValueError: each generator must be integral

        sage: R = EquationOrder([x^3 + x + 1, x^2 + 1/2], 'alpha'); R
        Traceback (most recent call last):
        ...
        ValueError: each generator must be integral
    """
    from sage.rings.number_field.number_field import NumberField
    R = ZZ['x']
    if isinstance(f, (list, tuple)):
        for g in f:
            try:
                R(g)
            except TypeError:
                raise ValueError('each generator must be integral')
    else:
        try:
            R(f)
        except TypeError:
            raise ValueError('each generator must be integral')

    K = NumberField(f, names=names, **kwds)
    return K.order(K.gens())


class Order(Parent, sage.rings.abc.Order):
    r"""
    An order in a number field.

    An order is a subring of the number field that has `\ZZ`-rank equal
    to the degree of the number field over `\QQ`.

    EXAMPLES::

        sage: x = polygen(ZZ, 'x')
        sage: K.<theta> = NumberField(x^4 + x + 17)
        sage: K.maximal_order()
        Maximal Order generated by theta in Number Field in theta with defining polynomial x^4 + x + 17
        sage: R = K.order(17*theta); R
        Order generated by 17*theta in Number Field in theta with defining polynomial x^4 + x + 17
        sage: R.basis()
        [1, 17*theta, 289*theta^2, 4913*theta^3]
        sage: R = K.order(17*theta, 13*theta); R
        Maximal Order generated by theta in Number Field in theta with defining polynomial x^4 + x + 17
        sage: R.basis()
        [1, theta, theta^2, theta^3]
        sage: R = K.order([34*theta, 17*theta + 17]); R
        Order generated by 17*theta in Number Field in theta with defining polynomial x^4 + x + 17
        sage: K.<b> = NumberField(x^4 + x^2 + 2)
        sage: (b^2).charpoly().factor()
        (x^2 + x + 2)^2
        sage: K.order(b^2)
        Traceback (most recent call last):
        ...
        ValueError: the rank of the span of gens is wrong

    Orders are always Noetherian::

        sage: x = polygen(ZZ, 'x')
        sage: L.<alpha> = NumberField(x**4 - x**2 + 7)
        sage: O = L.maximal_order() ; O.is_noetherian()
        True
        sage: E.<w> = NumberField(x^2 - x + 2)
        sage: OE = E.ring_of_integers(); OE.is_noetherian()
        True
    """

    def __init__(self, K):
        """
        This is called when creating an order to set the ambient field.

        EXAMPLES::

            sage: k = CyclotomicField(5)
            sage: k.maximal_order()
            Maximal Order generated by zeta5 in Cyclotomic Field of order 5 and degree 4

        TESTS::

            sage: x = polygen(ZZ, 'x')
            sage: k.<alg> = NumberField(x^7 + 3*x + 1, embedding=CC(0,1))
            sage: O = k.order(alg)
            sage: ordelt = O(alg)
            sage: CC(ordelt)
            0.0535229072603327 + 1.20934552493846*I
        """
        self._K = K
        cat = IntegralDomains() & NoetherianRings()
        Parent.__init__(self, base=ZZ, names=K.variable_names(),
                        normalize=False, category=cat)
        self._populate_coercion_lists_(embedding=self.number_field())
        if self.absolute_degree() == 2:
            self.is_maximal()       # cache

    def fractional_ideal(self, *args, **kwds):
        """
        Return the fractional ideal of the maximal order with given
        generators.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^2 + 2)
            sage: R = K.maximal_order()
            sage: R.fractional_ideal(2/3 + 7*a, a)
            Fractional ideal (1/3*a)
        """
        return self.number_field().fractional_ideal(*args, **kwds)

    def ideal(self, *args, **kwds):
        """
        Return the integral ideal with given generators.

        .. NOTE::

            This method constructs an ideal of this (not necessarily maximal) order.
            To construct a fractional ideal in the ambient number field, use
            :meth:`~sage.rings.number_field.number_field.NumberField_generic.fractional_ideal`.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^2 + 7)
            sage: R = K.maximal_order()
            sage: R.ideal([7*a, 77 + 28*a])
            Ideal (7/2*a + 7/2, 7*a) of Maximal Order generated by 1/2*a + 1/2 in Number Field in a with defining polynomial x^2 + 7
            sage: R = K.order(4*a)
            sage: R.ideal(8)
            Ideal (8, 32*a) of Order of conductor 8 generated by 4*a
             in Number Field in a with defining polynomial x^2 + 7

        This function is called implicitly below::

            sage: R = EquationOrder(x^2 + 2, 'a'); R
            Maximal Order generated by a in Number Field in a with defining polynomial x^2 + 2
            sage: (3,15)*R
            Ideal (3, 3*a) of Maximal Order generated by a in Number Field in a with defining polynomial x^2 + 2

        The zero ideal is handled properly::

            sage: R.ideal(0)
            Ideal (0) of Maximal Order generated by a in Number Field in a with defining polynomial x^2 + 2
        """
        # these keyword arguments are ignored since there used to be optional
        # arguments with these names for controlling deprecated/future behavior;
        # see #34806 and #35762
        if 'warn' in kwds:
            del kwds['warn']
        if 'future' in kwds:
            del kwds['future']
        from sage.rings.number_field.order_ideal import NumberFieldOrderIdeal
        return NumberFieldOrderIdeal(self, *args, **kwds)

    def _coerce_map_from_(self, R):
        """
        Orders currently only have coerce maps from the integers.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: k.<a> = NumberField(x^2 + 5077)
            sage: Ok = k.maximal_order()
            sage: Ok.has_coerce_map_from(k) #indirect doctest
            False
            sage: Ok.has_coerce_map_from(ZZ)
            True
        """
        return R is ZZ or R is int

    def __mul__(self, right):
        """
        Create an ideal in this order using the syntax ``O * gens``.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: k.<a> = NumberField(x^2 + 5077); G = k.class_group(); G
            Class group of order 22 with structure C22 of Number Field in a with defining polynomial x^2 + 5077
            sage: G.0 ^ -9
            Fractional ideal class (43, a + 13)
            sage: Ok = k.maximal_order(); Ok
            Maximal Order generated by a in Number Field in a with defining polynomial x^2 + 5077
            sage: Ok * (11, a + 7)
            Ideal (8*a + 1, 11*a) of Maximal Order generated by a in Number Field in a with defining polynomial x^2 + 5077
            sage: (11, a + 7) * Ok
            Ideal (8*a + 1, 11*a) of Maximal Order generated by a in Number Field in a with defining polynomial x^2 + 5077
        """
        return self.ideal(right)

    def __rmul__(self, left):
        """
        Create an ideal in this order using the syntax ``gens * O``.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: k.<a> = NumberField(x^2 + 431); G = k.class_group(); G
            Class group of order 21 with structure C21 of Number Field in a with defining polynomial x^2 + 431
            sage: G.0   # random output
            Fractional ideal class (6, 1/2*a + 11/2)
            sage: Ok = k.maximal_order(); Ok
            Maximal Order generated by 1/2*a + 1/2 in Number Field in a with defining polynomial x^2 + 431
            sage: (6, 1/2*a + 11/2)*Ok    # random output
            Fractional ideal (6, 1/2*a + 11/2)
            sage: 17*Ok
            Ideal (17/2*a + 17/2, 17*a) of Maximal Order generated by 1/2*a + 1/2 in Number Field in a with defining polynomial x^2 + 431
        """
        return self.ideal(left)

    def is_field(self, proof=True):
        r"""
        Return ``False`` (because an order is never a field).

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: L.<alpha> = NumberField(x**4 - x**2 + 7)
            sage: O = L.maximal_order() ; O.is_field()
            False
            sage: CyclotomicField(12).ring_of_integers().is_field()
            False
        """
        return False

    def is_integrally_closed(self) -> bool:
        r"""
        Return whether this ring is integrally closed.

        This is true if and only if it is equal
        to the maximal order.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^2 + 189*x + 394)
            sage: R = K.order(2*a)
            sage: R.is_integrally_closed()
            False
            sage: R
            Order of conductor 2 generated by 2*a in Number Field in a with defining polynomial x^2 + 189*x + 394
            sage: S = K.maximal_order(); S
            Maximal Order generated by a in Number Field in a with defining polynomial x^2 + 189*x + 394
            sage: S.is_integrally_closed()
            True
        """
        return self.is_maximal()

    def krull_dimension(self):
        r"""
        Return the Krull dimension of this order, which is 1.

        EXAMPLES::

            sage: K.<a> = QuadraticField(5)
            sage: OK = K.maximal_order()
            sage: OK.krull_dimension()
            1
            sage: O2 = K.order(2*a)
            sage: O2.krull_dimension()
            1
        """
        return ZZ.one()

    def integral_closure(self):
        r"""
        Return the integral closure of this order.

        EXAMPLES::

            sage: K.<a> = QuadraticField(5)
            sage: O2 = K.order(2*a); O2
            Order of conductor 4 generated by 2*a in Number Field in a
             with defining polynomial x^2 - 5 with a = 2.236067977499790?
            sage: O2.integral_closure()
            Maximal Order generated by 1/2*a + 1/2 in Number Field in a
             with defining polynomial x^2 - 5 with a = 2.236067977499790?
            sage: OK = K.maximal_order()
            sage: OK is OK.integral_closure()
            True
        """
        if self.is_maximal():
            return self
        else:
            return self.number_field().maximal_order()

    def gen(self, i):
        r"""
        Return `i`-th module generator of this order.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<c> = NumberField(x^3 + 2*x + 17)
            sage: O = K.maximal_order(); O
            Maximal Order generated by c in Number Field in c with defining polynomial x^3 + 2*x + 17
            sage: O.basis()
            [1, c, c^2]
            sage: O.gen(1)
            c
            sage: O.gen(2)
            c^2
            sage: O.gen(5)
            Traceback (most recent call last):
            ...
            IndexError: no 5th generator
            sage: O.gen(-1)
            Traceback (most recent call last):
            ...
            IndexError: no -1th generator
        """
        b = self.basis()
        if i < 0 or i >= len(b):
            raise IndexError("no %sth generator" % i)
        return self.basis()[i]

    def ngens(self):
        r"""
        Return the number of module generators of this order.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^3 + x^2 - 2*x + 8)
            sage: O = K.maximal_order()
            sage: O.ngens()
            3
        """
        return self.absolute_degree()

    def gens(self) -> tuple:
        """
        Return the generators as a tuple.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^3 + x^2 - 2*x + 8)
            sage: O = K.maximal_order()
            sage: O.gens()
            (1, 1/2*a^2 + 1/2*a, a^2)
        """
        return tuple(self.gen(i) for i in range(self.absolute_degree()))

    def basis(self):  # this must be defined in derived class
        r"""
        Return a basis over `\ZZ` of this order.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^3 + x^2 - 16*x + 16)
            sage: O = K.maximal_order(); O
            Maximal Order generated by 1/4*a^2 + 1/4*a in Number Field in a with defining polynomial x^3 + x^2 - 16*x + 16
            sage: O.basis()
            [1, 1/4*a^2 + 1/4*a, a^2]
        """
        raise NotImplementedError('child classes must implement')

    def coordinates(self, x):
        r"""
        Return the coordinate vector of `x` with respect to this order.

        INPUT:

        - ``x`` -- an element of the number field of this order

        OUTPUT:

        A vector of length `n` (the degree of the field) giving
        the coordinates of `x` with respect to the integral basis
        of the order.  In general this will be a vector of
        rationals; it will consist of integers if and only if `x`
        is in the order.

        AUTHOR: John Cremona  2008-11-15

        ALGORITHM:

        Uses linear algebra.  The change-of-basis matrix is
        cached.  Provides simpler implementations for
        :meth:`_contains_`, :meth:`is_integral` and :meth:`smallest_integer`.

        EXAMPLES::

            sage: K.<i> = QuadraticField(-1)
            sage: OK = K.ring_of_integers()
            sage: OK_basis = OK.basis(); OK_basis
            [1, i]
            sage: a = 23-14*i
            sage: acoords = OK.coordinates(a); acoords
            (23, -14)
            sage: sum([OK_basis[j]*acoords[j] for j in range(2)]) == a
            True
            sage: OK.coordinates((120+340*i)/8)
            (15, 85/2)

            sage: O = K.order(3*i)
            sage: O.is_maximal()
            False
            sage: O.index_in(OK)
            3
            sage: acoords = O.coordinates(a); acoords
            (23, -14/3)
            sage: sum([O.basis()[j]*acoords[j] for j in range(2)]) == a
            True
        """
        K = self.number_field()
        V, from_V, to_V = K.absolute_vector_space()

        try:
            M = self.__basis_matrix_inverse
        except AttributeError:
            from sage.matrix.constructor import Matrix
            self.__basis_matrix_inverse = Matrix([to_V(b) for b in self.basis()]).inverse()
            M = self.__basis_matrix_inverse
        return to_V(K(x)) * M

    def free_module(self):
        r"""
        Return the free `\ZZ`-module contained in the vector space
        associated to the ambient number field, that corresponds
        to this order.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^3 + x^2 - 2*x + 8)
            sage: O = K.maximal_order(); O.basis()
            [1, 1/2*a^2 + 1/2*a, a^2]
            sage: O.free_module()
            Free module of degree 3 and rank 3 over Integer Ring
            User basis matrix:
            [  1   0   0]
            [  0 1/2 1/2]
            [  0   0   1]

        An example in a relative extension.  Notice that the module is
        a `\ZZ`-module in the absolute field associated to the relative
        field::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a,b> = NumberField([x^2 + 1, x^2 + 2])
            sage: O = K.maximal_order(); O.basis()
            [(-3/2*b - 5)*a + 7/2*b - 2, -3*a + 2*b, -2*b*a - 3, -7*a + 5*b]
            sage: O.free_module()
            Free module of degree 4 and rank 4 over Integer Ring
            User basis matrix:
            [1/4 1/4 3/4 3/4]
            [  0 1/2   0 1/2]
            [  0   0   1   0]
            [  0   0   0   1]
        """
        try:
            return self.__free_module
        except AttributeError:
            pass
        from sage.rings.number_field.number_field_ideal import basis_to_module
        M = basis_to_module(self.basis(), self.number_field())
        self.__free_module = M
        return M

    @cached_method
    def ring_generators(self):
        """
        Return generators for ``self`` as a ring.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<i> = NumberField(x^2 + 1)
            sage: O = K.maximal_order(); O
            Gaussian Integers generated by i in Number Field in i with defining polynomial x^2 + 1
            sage: O.ring_generators()
            [i]

        This is an example where 2 generators are required (because 2 is an essential
        discriminant divisor).::

            sage: K.<a> = NumberField(x^3 + x^2 - 2*x + 8)
            sage: O = K.maximal_order(); O.basis()
            [1, 1/2*a^2 + 1/2*a, a^2]
            sage: O.ring_generators()
            [1/2*a^2 + 1/2*a, a^2]

        An example in a relative number field::

            sage: K.<a, b> = NumberField([x^2 + x + 1, x^3 - 3])
            sage: O = K.maximal_order()
            sage: O.ring_generators()
            [(-5/3*b^2 + 3*b - 2)*a - 7/3*b^2 + b + 3,
             (-5*b^2 - 9)*a - 5*b^2 - b,
             (-6*b^2 - 11)*a - 6*b^2 - b]
        """
        K = self._K
        n = []
        V, from_V, to_V = self._K.absolute_vector_space()
        A = ZZ**K.absolute_degree()
        remaining = [x for x in self.basis() if x != 1]
        gens = []
        while remaining:
            g = remaining.pop(0)
            gens.append(g)
            n.append(g.absolute_minpoly().degree())
            W = A.span([to_V(x) for x in monomials(gens, n)])
            remaining = [x for x in remaining if to_V(x) not in W]
        return Sequence(gens, immutable=True)

    @cached_method
    def _defining_names(self):
        """
        Return the generators of the ambient number field, but with
        this order as parent.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: B.<z> = EquationOrder(x^2 + 3)
            sage: B._defining_names()
            (z,)

        For relative extensions::

            sage: O.<a,b> = EquationOrder([x^2 + 1, x^2 + 2])
            sage: O._defining_names()
            (a, b)
        """
        gens = self.number_field().gens()
        return tuple(self(g) for g in gens)

    def zeta(self, n=2, all=False):
        r"""
        Return a primitive `n`-th root of unity in this order, if it
        contains one. If ``all`` is ``True``, return all of them.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: F.<alpha> = NumberField(x**2 + 3)
            sage: F.ring_of_integers().zeta(6)
            -1/2*alpha + 1/2
            sage: O = F.order([3*alpha])
            sage: O.zeta(3)
            Traceback (most recent call last):
            ...
            ArithmeticError: there are no 3rd roots of unity in self
        """
        roots_in_field = self.number_field().zeta(n, True)
        roots_in_self = [self(x) for x in roots_in_field if x in self]
        if not roots_in_self:
            if all:
                return []
            else:
                raise ArithmeticError("there are no %s roots of unity in self" % n.ordinal_str())
        if all:
            return roots_in_self
        else:
            return roots_in_self[0]

    def number_field(self):
        """
        Return the number field of this order, which is the ambient
        number field that this order is embedded in.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<b> = NumberField(x^4 + x^2 + 2)
            sage: O = K.order(2*b); O
            Order generated by 2*b in Number Field in b with defining polynomial x^4 + x^2 + 2
            sage: O.basis()
            [1, 2*b, 4*b^2, 8*b^3]
            sage: O.number_field()
            Number Field in b with defining polynomial x^4 + x^2 + 2
            sage: O.number_field() is K
            True
        """
        return self._K

    def ambient(self):
        r"""
        Return the ambient number field that contains ``self``.

        This is the same as :meth:`number_field` and
        :meth:`fraction_field`

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: k.<z> = NumberField(x^2 - 389)
            sage: o = k.order(389*z + 1)
            sage: o
            Order of conductor 778 generated by 389*z in Number Field in z with defining polynomial x^2 - 389
            sage: o.basis()
            [1, 389*z]
            sage: o.ambient()
            Number Field in z with defining polynomial x^2 - 389
        """
        return self._K

    def residue_field(self, prime, names=None, check=False):
        """
        Return the residue field of this order at a given prime, i.e., `O/pO`.

        INPUT:

        - ``prime`` -- a prime ideal of the maximal order in this number field
        - ``names`` -- the name of the variable in the residue field
        - ``check`` -- whether or not to check the primality of prime

        OUTPUT: the residue field at this prime

        EXAMPLES::

            sage: R.<x> = QQ[]
            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^4 + 3*x^2 - 17)
            sage: P = K.ideal(61).factor()[0][0]
            sage: OK = K.maximal_order()
            sage: OK.residue_field(P)
            Residue field in abar of Fractional ideal (61, a^2 + 30)
            sage: Fp.<b> = OK.residue_field(P)
            sage: Fp
            Residue field in b of Fractional ideal (61, a^2 + 30)
        """
        if self.is_maximal():
            return self.number_field().residue_field(prime, names, check=check)

        raise NotImplementedError("residue fields of non-maximal orders "
                                  "are not yet supported")

    def fraction_field(self):
        """
        Return the fraction field of this order, which is the
        ambient number field.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<b> = NumberField(x^4 + 17*x^2 + 17)
            sage: O = K.order(17*b); O
            Order generated by 17*b in Number Field in b with defining polynomial x^4 + 17*x^2 + 17
            sage: O.fraction_field()
            Number Field in b with defining polynomial x^4 + 17*x^2 + 17
        """
        return self._K

    def degree(self):
        r"""
        Return the degree of this order, which is the rank of this order as a
        `\ZZ`-module.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: k.<c> = NumberField(x^3 + x^2 - 2*x+8)
            sage: o = k.maximal_order()
            sage: o.degree()
            3
            sage: o.rank()
            3
        """
        return self._K.degree()

    def rank(self):
        r"""
        Return the rank of this order, which is the rank of the underlying
        `\ZZ`-module, or the degree of the ambient number field that contains
        this order.

        This is a synonym for :meth:`degree`.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: k.<c> = NumberField(x^5 + x^2 + 1)
            sage: o = k.maximal_order(); o
            Maximal Order generated by c in Number Field in c with defining polynomial x^5 + x^2 + 1
            sage: o.rank()
            5
        """
        return self.degree()

    def class_number(self, proof=None):
        r"""
        Return the class number of this order.

        .. NOTE::

            For some applications (e.g., in algorithms for computing
            class groups) it is required to merely *approximate* the
            class number. The function
            :func:`quadratic_order_approximate_class_number`
            can be used to compute such an approximation (currently
            restricted to maximal imaginary-quadratic orders).

        EXAMPLES::

            sage: ZZ[2^(1/3)].class_number()                                            # needs fpylll sage.symbolic
            1
            sage: QQ[sqrt(-23)].maximal_order().class_number()                          # needs fpylll sage.symbolic
            3
            sage: ZZ[120*sqrt(-23)].class_number()                                      # needs fpylll sage.symbolic
            288

        Note that non-maximal orders are only supported in quadratic fields::

            sage: ZZ[120*sqrt(-23)].class_number()                                      # needs fpylll sage.symbolic
            288
            sage: ZZ[100*sqrt(3)].class_number()                                        # needs fpylll sage.symbolic
            4
            sage: ZZ[11*2^(1/3)].class_number()                                         # needs fpylll sage.symbolic
            Traceback (most recent call last):
            ...
            NotImplementedError: computation of class numbers of non-maximal orders
            not in quadratic fields is not implemented

        TESTS:

        Test for PARI bug #2466::

            sage: x = polygen(ZZ)
            sage: R.<t> = EquationOrder(x^2 - 8461)
            sage: R.class_number()
            3
        """
        if not self.is_maximal():
            K = self.number_field()
            if K.degree() != 2:
                raise NotImplementedError("computation of class numbers of non-maximal orders not in quadratic fields is not implemented")
            return quadratic_order_class_number(self.discriminant())
        return self.number_field().class_number(proof=proof)

    def class_group(self, proof=None, names='c'):
        r"""
        Return the class group of this order.

        (Currently only implemented for the maximal order.)

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: k.<a> = NumberField(x^2 + 5077)
            sage: O = k.maximal_order(); O
            Maximal Order generated by a in Number Field in a with defining polynomial x^2 + 5077
            sage: O.class_group()
            Class group of order 22 with structure C22 of
             Number Field in a with defining polynomial x^2 + 5077
        """
        if self.is_maximal():
            return self.number_field().class_group(proof=proof, names=names)
        else:
            raise NotImplementedError('non-maximal orders are not yet supported')

    def is_suborder(self, other):
        """
        Return ``True`` if ``self`` and ``other`` are both orders in the
        same ambient number field and ``self`` is a subset of ``other``.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: W.<i> = NumberField(x^2 + 1)
            sage: O5 = W.order(5*i)
            sage: O10 = W.order(10*i)
            sage: O15 = W.order(15*i)
            sage: O15.is_suborder(O5)
            True
            sage: O5.is_suborder(O15)
            False
            sage: O10.is_suborder(O15)
            False

        We create another isomorphic but different field::

            sage: W2.<j> = NumberField(x^2 + 1)
            sage: P5 = W2.order(5*j)

        This is ``False`` because the ambient number fields are not equal.::

            sage: O5.is_suborder(P5)
            False

        We create a field that contains (in no natural way!) `W`,
        and of course again :meth:`is_suborder` returns False::

            sage: K.<z> = NumberField(x^4 + 1)
            sage: M = K.order(5*z)
            sage: O5.is_suborder(M)
            False
        """
        if not isinstance(other, Order):
            return False
        if other.number_field() != self.number_field():
            return False
        return self.module().is_submodule(other.module())

    def __eq__(self, other):
        r"""
        Check whether the order ``self`` is equal to ``other``.

        .. NOTE::

            This method is just for equality. If you want to check if
            ``self`` is contained in ``other``, use instead
            ``self.is_suborder(other)`` to determine inclusion.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^3 + 2)
            sage: O1 = K.order(a); O1
            Order generated by a in Number Field in a with defining polynomial x^3 + 2
            sage: O2 = K.order(a^2); O2
            Order generated by [2*a, a^2] in Number Field in a with defining polynomial x^3 + 2
            sage: O1 == O2
            False

            sage: O1 == K
            False
            sage: K == O1
            False

        Here is how to check for inclusion::

            sage: O2.is_suborder(O1)
            True
        """
        if not isinstance(other, Order):
            return False
        if self._K != other._K:
            return False
        if self is other:
            return True
        return self._module_rep == other._module_rep

    def __ne__(self, other):
        """
        Check whether the order ``self`` is not equal to ``other``.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^3 + 2)
            sage: O1 = K.order(a); O1
            Order generated by a in Number Field in a with defining polynomial x^3 + 2
            sage: O2 = K.order(a^2); O2
            Order generated by [2*a, a^2] in Number Field in a with defining polynomial x^3 + 2
            sage: O1 != O2
            True
        """
        return not (self == other)

    def __hash__(self):
        """
        Compute the hash of ``self``.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^3 + 2)
            sage: L.<b> = NumberField(x^3 + 3)
            sage: O1 = K.order(a)
            sage: hash(O1) == hash(K.order(a))
            True
            sage: hash(O1) == hash(K.order(a^2))
            False
            sage: hash(O1) == hash(L.order(b))
            False
        """
        return hash((self._K, self._module_rep))

    def conductor(self):
        r"""
        For orders in *quadratic* number fields, return the conductor
        of this order.

        The conductor is the unique positive integer `f` such that
        the discriminant of this order is `f^2` times the discriminant
        of the containing quadratic field.

        Not implemented for orders in number fields of degree `\neq 2`.

        .. SEEALSO ::

            :meth:`sage.rings.number_field.number_field.NumberField_quadratic.order_of_conductor`

        EXAMPLES::

            sage: K.<t> = QuadraticField(-101)
            sage: K.maximal_order().conductor()
            1
            sage: K.order(5*t).conductor()
            5
            sage: K.discriminant().factor()
            -1 * 2^2 * 101
            sage: K.order(5*t).discriminant().factor()
            -1 * 2^2 * 5^2 * 101

        TESTS::

            sage: type(K.order(5*t).conductor())
            <class 'sage.rings.integer.Integer'>
        """
        if not isinstance(self._K, sage.rings.abc.NumberField_quadratic):
            raise NotImplementedError('not implemented for number fields of degree != 2')
        D = self.discriminant()
        D0 = self._K.discriminant()
        return (D // D0).sqrt()

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

        INPUT:

        - ``args``, ``kwds`` -- parameters passed to the random
          integer function.  See the documentation for
          ``ZZ.random_element()`` for details.

        OUTPUT:

        A random element of this order, computed as a random
        `\ZZ`-linear combination of the basis.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^3 + 2)
            sage: OK = K.ring_of_integers()
            sage: OK.random_element() # random output
            -2*a^2 - a - 2
            sage: OK.random_element(distribution='uniform') # random output
            -a^2 - 1
            sage: OK.random_element(-10,10) # random output
            -10*a^2 - 9*a - 2
            sage: K.order(a).random_element() # random output
            a^2 - a - 3

        ::

            sage: K.<z> = CyclotomicField(17)
            sage: OK = K.ring_of_integers()
            sage: OK.random_element() # random output
            z^15 - z^11 - z^10 - 4*z^9 + z^8 + 2*z^7 + z^6
             - 2*z^5 - z^4 - 445*z^3 - 2*z^2 - 15*z - 2
            sage: OK.random_element().is_integral()
            True
            sage: OK.random_element().parent() is OK
            True

        A relative example::

            sage: K.<a, b> = NumberField([x^2 + 2, x^2 + 1000*x + 1])
            sage: OK = K.ring_of_integers()
            sage: OK.random_element() # random output
            (42221/2*b + 61/2)*a + 7037384*b + 7041
            sage: OK.random_element().is_integral() # random output
            True
            sage: OK.random_element().parent() is OK # random output
            True

        An example in a non-maximal order::

            sage: K.<a> = QuadraticField(-3)
            sage: R = K.ring_of_integers()
            sage: A = K.order(a)
            sage: A.index_in(R)
            2
            sage: R.random_element() # random output
            -39/2*a - 1/2
            sage: A.random_element() # random output
            2*a - 1
            sage: A.random_element().is_integral()
            True
            sage: A.random_element().parent() is A
            True
        """
        return sum([ZZ.random_element(*args, **kwds) * a
                    for a in self.basis()])

    def absolute_degree(self):
        r"""
        Return the absolute degree of this order, i.e., the degree of this order over `\ZZ`.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^3 + 2)
            sage: O = K.maximal_order()
            sage: O.absolute_degree()
            3
        """
        return self.number_field().absolute_degree()

    def valuation(self, p):
        r"""
        Return the `p`-adic valuation on this order.

        EXAMPLES:

        The valuation can be specified with an integer prime `p` that is
        completely ramified or unramified::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^2 + 1)
            sage: O = K.order(2*a)
            sage: valuations.pAdicValuation(O, 2)                                       # needs sage.geometry.polyhedron
            2-adic valuation

            sage: GaussianIntegers().valuation(2)                                       # needs sage.geometry.polyhedron
            2-adic valuation

        ::

            sage: GaussianIntegers().valuation(3)                                       # needs sage.geometry.polyhedron
            3-adic valuation

        A prime `p` that factors into pairwise distinct factors, results in an error::

            sage: GaussianIntegers().valuation(5)                                       # needs sage.geometry.polyhedron
            Traceback (most recent call last):
            ...
            ValueError: The valuation Gauss valuation induced by 5-adic valuation does not
            approximate a unique extension of 5-adic valuation with respect to x^2 + 1

        The valuation can also be selected by giving a valuation on the base
        ring that extends uniquely::

            sage: CyclotomicField(5).ring_of_integers().valuation(ZZ.valuation(5))      # needs sage.geometry.polyhedron
            5-adic valuation

        When the extension is not unique, this does not work::

            sage: GaussianIntegers().valuation(ZZ.valuation(5))                         # needs sage.geometry.polyhedron
            Traceback (most recent call last):
            ...
            ValueError: The valuation Gauss valuation induced by 5-adic valuation does not
            approximate a unique extension of 5-adic valuation with respect to x^2 + 1

        If the fraction field is of the form `K[x]/(G)`, you can specify a
        valuation by providing a discrete pseudo-valuation on `K[x]` which
        sends `G` to infinity::

            sage: # needs sage.geometry.polyhedron
            sage: R.<x> = QQ[]
            sage: GV5 = GaussValuation(R, QQ.valuation(5))
            sage: v = GaussianIntegers().valuation(GV5.augmentation(x + 2, infinity))
            sage: w = GaussianIntegers().valuation(GV5.augmentation(x + 1/2, infinity))
            sage: v == w
            False

        .. SEEALSO::

            :meth:`NumberField_generic.valuation() <sage.rings.number_field.number_field.NumberField_generic.valuation>`,
            :meth:`pAdicGeneric.valuation() <sage.rings.padics.padic_generic.pAdicGeneric.valuation>`
        """
        from sage.rings.padics.padic_valuation import pAdicValuation
        return pAdicValuation(self, p)

    def some_elements(self):
        """
        Return a list of elements of the given order.

        EXAMPLES::

            sage: G = GaussianIntegers(); G
            Gaussian Integers generated by I in Number Field in I with defining polynomial x^2 + 1 with I = 1*I
            sage: G.some_elements()
            [1, I, 2*I, -1, 0, -I, 2, 4*I, -2, -2*I, -4]

            sage: R.<t> = QQ[]
            sage: K.<a> = QQ.extension(t^3 - 2); K
            Number Field in a with defining polynomial t^3 - 2
            sage: Z = K.ring_of_integers(); Z
            Maximal Order generated by a in Number Field in a with defining polynomial t^3 - 2
            sage: Z.some_elements()
            [1, a, a^2, 2*a, 0, 2, a^2 + 2*a + 1, ..., a^2 + 1, 2*a^2 + 2, a^2 + 2*a, 4*a^2 + 4]

        TESTS:

        This also works for trivial extensions::

            sage: R.<t> = QQ[]
            sage: K.<a> = QQ.extension(t); K
            Number Field in a with defining polynomial t
            sage: Z = K.ring_of_integers(); Z
            Maximal Order generated by [] in Number Field in a with defining polynomial t
            sage: Z.some_elements()
            [1, 0, 2, -1, -2, 4]
        """
        elements = list(self.basis())
        for a in self.fraction_field().some_elements():
            if a in self and a not in elements:
                elements.append(self(a))
        return elements

#     def absolute_polynomial(self):
#         """
#         Return the absolute polynomial of this order, which is just the absolute polynomial of the number field.

#         EXAMPLES::

#         sage: K.<a, b> = NumberField([x^2 + 1, x^3 + x + 1]); OK = K.maximal_order()
#         Traceback (most recent call last):
#         ...
#         NotImplementedError

#         #sage: OK.absolute_polynomial()
#         #x^6 + 5*x^4 - 2*x^3 + 4*x^2 + 4*x + 1
#         """
#         return self.number_field().absolute_polynomial()

#     def polynomial(self):
#         """
#         Return the polynomial defining the number field that contains self.
#         """
#         return self.number_field().polynomial()

#     def polynomial_ntl(self):
#         """
#         Return defining polynomial of the parent number field as a
#         pair, an ntl polynomial and a denominator.

#         This is used mainly to implement some internal arithmetic.

#         EXAMPLES::

#             sage: NumberField(x^2 + 1,'a').maximal_order().polynomial_ntl()
#             ([1 0 1], 1)
#         """
#         return self.number_field().polynomial_ntl()


class Order_absolute(Order):
    def __init__(self, K, module_rep):
        """
        EXAMPLES::

            sage: from sage.rings.number_field.order import *
            sage: x = polygen(QQ)
            sage: K.<a> = NumberField(x^3 + 2)
            sage: V, from_v, to_v = K.vector_space()
            sage: M = span([to_v(a^2), to_v(a), to_v(1)],ZZ)
            sage: O = AbsoluteOrder(K, M); O
            Maximal Order generated by a in Number Field in a with defining polynomial x^3 + 2

            sage: M = span([to_v(a^2), to_v(a), to_v(2)],ZZ)
            sage: O = AbsoluteOrder(K, M); O
            Traceback (most recent call last):
            ...
            ValueError: 1 is not in the span of the module, hence not an order

        TESTS::

            sage: loads(dumps(O)) is O
            True
            sage: TestSuite(O).run()
        """
        if K.degree() == 2:
            self._element_type = OrderElement_quadratic
            # adding the following attribute makes the comparison of elements
            # faster.
            self._standard_embedding = K._standard_embedding
        else:
            self._element_type = OrderElement_absolute

        # Whether this order is the maximal order, or None if we have not found out yet.
        self.__is_maximal = None
        # Maps each prime to whether this order is maximal at that prime.
        self.__is_maximal_at = {}

        self._module_rep = module_rep
        Order.__init__(self, K)

        if self.absolute_degree() == 2:
            self.discriminant()     # cache

    def _element_constructor_(self, x):
        r"""
        Coerce ``x`` into this order.

        EXAMPLES::

            sage: x = polygen(QQ)
            sage: k.<z> = NumberField(x^2 - 389)
            sage: m = k.order(3*z); m
            Order of conductor 6 generated by 3*z in Number Field in z with defining polynomial x^2 - 389
            sage: m(6*z)
            6*z
            sage: k(m(6*z))
            6*z

        If ``x`` is a list or tuple the element constructed is the
        linear combination of the generators with these coefficients
        (see :issue:`10017`)::

            sage: x = polygen(QQ)
            sage: K.<a> = NumberField(x^3 - 10)
            sage: ZK = K.ring_of_integers()
            sage: ZK.basis()
            [1/3*a^2 + 1/3*a + 1/3, a, a^2]
            sage: ZK([1,2,3])
            10/3*a^2 + 7/3*a + 1/3
            sage: K([1,2,3])
            3*a^2 + 2*a + 1
        """
        if isinstance(x, (tuple, list)):
            x = sum(xi * gi for xi, gi in zip(x, self.gens()))
        if not isinstance(x, Element) or x.parent() is not self._K:
            x = self._K(x)
        V, _, embedding = self._K.vector_space()
        if embedding(x) not in self._module_rep:
            raise TypeError("Not an element of the order.")
        return self._element_type(self, x)

    def __add__(left, right):
        """
        Add two orders.

        EXAMPLES::

            sage: K.<a> = NumberField(polygen(QQ,'z')^3 - 2)
            sage: O6 = K.order(6*a); O6
            Order generated by 6*a in Number Field in a with defining polynomial z^3 - 2
            sage: O6.basis()
            [1, 6*a, 36*a^2]
            sage: O15 = K.order(15*a^2); O15.basis()
            [1, 450*a, 15*a^2]
            sage: R = O6 + O15; R
            Order generated by [6*a, 3*a^2] in Number Field in a with defining polynomial z^3 - 2
            sage: R.basis()
            [1, 6*a, 3*a^2]
        """
        if not isinstance(right, Order_absolute):
            raise NotImplementedError("cannot add these orders yet")

        if left.number_field() != right.number_field():
            raise TypeError("number fields do not match")

        if left._is_maximal():
            return left

        elif right._is_maximal():
            return right

        return AbsoluteOrder(left._K, left._module_rep + right._module_rep)

    def __and__(left, right):
        """
        Intersect orders.

        EXAMPLES::

            sage: K.<i> = QuadraticField(-1)
            sage: O3 = K.order(3*i); O5 = K.order(5*i)
            sage: R = O3 & O5; R
            Order of conductor 15 generated by 15*i in Number Field in i with defining polynomial x^2 + 1 with i = 1*I
            sage: R.basis()
            [1, 15*i]
            sage: O3.intersection(O5).basis()
            [1, 15*i]

        TESTS:

        Verify that :issue:`33386` has been resolved::

            sage: (K.maximal_order() & K.maximal_order()).is_maximal()
            True

        Verify that an absolute order can be intersected with a relative order::

            sage: x = polygen(ZZ, 'x')
            sage: L.<a> = K.extension(x^2 - 2)
            sage: L.absolute_field('z').maximal_order() & L.maximal_order()
            Maximal Order generated by [7/12*z^3 + 3/4*z^2 + 1/12*z + 1/4, 1/6*z^3 + 1/6*z, z^2] in Number Field in z with defining polynomial x^4 - 2*x^2 + 9
            sage: L.maximal_order() & L.absolute_field('z').maximal_order()
            Maximal Order generated by [7/12*z^3 + 3/4*z^2 + 1/12*z + 1/4, 1/6*z^3 + 1/6*z, z^2] in Number Field in z with defining polynomial x^4 - 2*x^2 + 9
        """
        if isinstance(right, Order_relative):
            return right & left

        if left.number_field() != right.number_field():
            raise TypeError("number fields do not match")

        is_maximal = None

        # Note that this is not correct while orders created with
        # non-maximal-non-unique are still around. Once that deprecation has
        # been removed, these simple rules can be enabled.
        # if left._is_maximal() is True and right._is_maximal() is True:
        #     is_maximal = True
        # if left._is_maximal() is False or right._is_maximal() is False:
        #     is_maximal = False

        return AbsoluteOrder(left._K, left._module_rep.intersection(right._module_rep), is_maximal=is_maximal)

    def _magma_init_(self, magma):
        """
        Return Magma version of this absolute order.

        INPUT:

        - ``magma`` -- a magma interpreter

        OUTPUT: a :class:`MagmaElement`, the magma version of this absolute order

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^3 + 2) # optional - magma
            sage: magma(K.maximal_order())  # optional - magma
            Equation Order with defining polynomial x^3 + 2 over its ground order

        _magma_init_ was called implicitly by the above call::

            sage: K.maximal_order()._magma_init_(magma) # optional - magma
            'Order([(_sage_[...]![1, 0, 0]),(_sage_[...]![0, 1, 0]),(_sage_[...]![0, 0, 1])])'
        """
        K = self.number_field()
        v = (K(a)._magma_init_(magma) for a in self.basis())
        return 'Order([{}])'.format(','.join(v))

    def discriminant(self):
        """
        Return the discriminant of this order.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^8 + x^3 - 13*x + 26)
            sage: O = K.maximal_order()
            sage: factor(O.discriminant())
            3 * 11 * 13^2 * 613 * 1575917857
            sage: L = K.order(13*a^2)
            sage: factor(L.discriminant())
            3^3 * 5^2 * 11 * 13^60 * 613 * 733^2 * 1575917857
            sage: factor(L.index_in(O))
            3 * 5 * 13^29 * 733
            sage: L.discriminant() / O.discriminant() == L.index_in(O)^2
            True


        TESTS::

            sage: type(K.order(5*a).discriminant())
            <class 'sage.rings.integer.Integer'>

        This should be fast (:issue:`40770`)::

            sage: x = polygen(ZZ, 'x')
            sage: f = -10200*x^5 + 3394506606*x^4 + 1499062700037543*x^3 - 399446093061413660294*x^2 - 54234952557577515347321243*x + 2514415152433747751031436303788
            sage: K.<a> = NumberField(f)
            sage: easy = [2,3,5,7,11,83,5443,3548737,108743131120471]
            sage: OK = K.maximal_order(v=easy, assume_maximal=True)
            sage: OK.discriminant()
            -2233837184359702514053503341104978970680899423438448397157179110318387386336251895416563127827690136506493208269682596127007739109465589455

        """
        try:
            return self.__discriminant
        except AttributeError:
            D = ZZ(self._K.discriminant(self.basis()))
            self.__discriminant = D
            return D

    absolute_discriminant = discriminant

    def is_maximal(self, p=None):
        """
        Return whether this is the maximal order.

        INPUT:

        - ``p`` -- integer prime or ``None`` (default: ``None``); if
          set, return whether this order is maximal at the prime `p`

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<i> = NumberField(x^2 + 1)

            sage: K.order(3*i).is_maximal()
            False
            sage: K.order(5*i).is_maximal()
            False
            sage: (K.order(3*i) + K.order(5*i)).is_maximal()
            True
            sage: K.maximal_order().is_maximal()
            True

        Maximality can be checked at primes when the order is maximal at that
        prime by construction::

            sage: K.maximal_order().is_maximal(p=3)
            True

        And also at other primes::

            sage: K.order(3*i).is_maximal(p=3)
            False

         An example involving a relative order::

            sage: K.<a, b> = NumberField([x^2 + 1, x^2 - 3])
            sage: O = K.order([3*a, 2*b])
            sage: O.is_maximal()
            False
        """
        if self._is_maximal() is True:
            return True

        if p is None:
            if self._is_maximal() is None:
                self._assume_maximal(self.absolute_discriminant() == self._K.absolute_discriminant())
            return self._is_maximal()
        else:
            p = ZZ(p).abs()

            if self._is_maximal_at(p) is None:
                is_maximal = self._K.maximal_order(p, assume_maximal=None).absolute_discriminant().valuation(p) == self.absolute_discriminant().valuation(p)
                self._assume_maximal(is_maximal, p=p)

            return self._is_maximal_at(p)

    def _is_maximal(self):
        r"""
        Return whether this order is already known to be maximal.

        Used by :meth:`is_maximal`.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<t> = NumberField(x^3 + x + 1)
            sage: K.order(1337*t)._is_maximal() is None
            True
            sage: K.order(1337*t).is_maximal()
            False
            sage: K.order(1337*t)._is_maximal()
            False
        """
        return self.__is_maximal

    def _is_maximal_at(self, p=None):
        r"""
        Return whether this order is already known to be maximal at ``p``.

        When no ``p`` is specified, returns a dictionary of primes for which
        maximality is known.

        Used by :meth:`is_maximal`.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^13 - 2)

            sage: O = K.order(a)
            sage: O._is_maximal_at(p=1361) is None
            True
            sage: O._assume_maximal(p=1361) is O
            True
            sage: K.order(a).is_maximal(p=1361)
            True
            sage: K.order(a)._is_maximal_at(p=1361)
            True

        TESTS::

            sage: L.<a, b> = NumberField([x^2 - 1000005, x^2 - 5*1000099^2])
            sage: K = L.absolute_field('c')
            sage: O = K.maximal_order([13], assume_maximal=None)
            sage: O._is_maximal_at()
            {13: True}
        """
        if p is None:
            return dict(self.__is_maximal_at)

        p = ZZ(p).abs()
        return self.__is_maximal_at.get(p, None)

    def _assume_maximal(self, is_maximal=True, p=None):
        r"""
        Record that this order ``is_maximal`` at the integer prime ``p``.

        To support the deprecated behavior for
        ``is_maximal="non-maximal-non-unique"``, this returns an order.
        Typically, the order itself.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^4 - 10001822082820*x^2 + 25009091240356266913960000)
            sage: O = K.maximal_order([13], assume_maximal=None)

        We can store information about more primes::

            sage: O._is_maximal_at(p=7) is None
            True
            sage: 7.divides(K.absolute_discriminant())
            False
            sage: O._assume_maximal(p=7) is O
            True
            sage: O._is_maximal_at(p=7)
            True

        We cannot store contradicting information at a prime::

            sage: O._assume_maximal(p=7, is_maximal=False)
            Traceback (most recent call last):
            ...
            ValueError: cannot assume this order to be non-maximal at 7 because we already found it to be maximal at that prime

        We can safely store information that we know to be wrong to support
        legacy behavior of orders that are assumed to be only maximal at some
        primes::

            sage: K.<i> = NumberField(x^2 + 1)
            sage: O = K.order(1+i)
            sage: O.is_maximal()
            True
            sage: N = O._assume_maximal(is_maximal='non-maximal-non-unique')
            sage: N._assume_maximal(p=2) is N
            True
            sage: N is O
            False
            sage: N == O
            True
            sage: N.is_maximal()
            False
            sage: N.is_maximal(p=2)
            True
        """
        if is_maximal is None:
            # No assumption made, return the object unchanged.
            return self

        if p is None:
            if is_maximal == "non-maximal-non-unique":
                # We force this order to be non-maximal to support legacy code that
                # could create such orders.
                self = type(self)(self._K, self._module_rep)
                self.__is_maximal = False
            elif is_maximal:
                if self._is_maximal() is False:
                    raise ValueError("cannot assume this order to be maximal because we already found it to be a non-maximal order")
                self.__is_maximal = True
                # No need to keep information at specific primes anymore.
                self.__is_maximal_at = {}
            else:
                if self._is_maximal() is True:
                    raise ValueError("cannot assume this order to be non-maximal because we already found it to be a maximal order")
                self.__is_maximal = False
        else:
            p = ZZ(p).abs()

            if is_maximal == "non-maximal-non-unique":
                raise NotImplementedError("legacy support for explicitly non-maximal orders only possible at all primes")
            elif is_maximal:
                if self._is_maximal_at(p) is False:
                    raise ValueError(f"cannot assume this order to be maximal at {p} because we already found it to be non-maximal at that prime")
                self.__is_maximal_at[p] = True
            else:
                if self._is_maximal_at(p) is True:
                    raise ValueError(f"cannot assume this order to be non-maximal at {p} because we already found it to be maximal at that prime")

                self._assume_maximal(False)
                self.__is_maximal_at[p] = False

        return self

    def change_names(self, names):
        """
        Return a new order isomorphic to this one in the number field with
        given variable names.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: R = EquationOrder(x^3 + x + 1, 'alpha'); R
            Order generated by alpha in Number Field in alpha with defining polynomial x^3 + x + 1
            sage: R.basis()
            [1, alpha, alpha^2]
            sage: S = R.change_names('gamma'); S
            Order generated by gamma in Number Field in gamma with defining polynomial x^3 + x + 1
            sage: S.basis()
            [1, gamma, gamma^2]
        """
        K = self.number_field().change_names(names)
        _, to_K = K.structure()
        B = [to_K(a) for a in self.basis()]
        return K.order(B, check_is_integral=False, check_rank=False, allow_subfield=True)

    def index_in(self, other):
        """
        Return the index of ``self`` in ``other``.

        This is a lattice index,
        so it is a rational number if ``self`` is not contained in ``other``.

        INPUT:

        - ``other`` -- another absolute order with the same ambient number field

        OUTPUT: a rational number

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: k.<i> = NumberField(x^2 + 1)
            sage: O1 = k.order(i)
            sage: O5 = k.order(5*i)
            sage: O5.index_in(O1)
            5

            sage: k.<a> = NumberField(x^3 + x^2 - 2*x+8)
            sage: o = k.maximal_order()
            sage: o
            Maximal Order generated by [1/2*a^2 + 1/2*a, a^2] in Number Field in a with defining polynomial x^3 + x^2 - 2*x + 8
            sage: O1 = k.order(a); O1
            Order generated by a in Number Field in a with defining polynomial x^3 + x^2 - 2*x + 8
            sage: O1.index_in(o)
            2
            sage: O2 = k.order(1+2*a); O2
            Order generated by 2*a in Number Field in a with defining polynomial x^3 + x^2 - 2*x + 8
            sage: O1.basis()
            [1, a, a^2]
            sage: O2.basis()
            [1, 2*a, 4*a^2]
            sage: o.index_in(O2)
            1/16
        """
        if not isinstance(other, Order_absolute):
            raise TypeError("other must be an absolute order.")
        if other.ambient() != self.ambient():
            raise ValueError("other must have the same ambient number field as self.")
        return self._module_rep.index_in(other._module_rep)

    def module(self):
        """
        Return the underlying free module corresponding to this
        order, embedded in the vector space corresponding to the
        ambient number field.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: k.<a> = NumberField(x^3 + x + 3)
            sage: m = k.order(3*a); m
            Order generated by 3*a in Number Field in a with defining polynomial x^3 + x + 3
            sage: m.module()
            Free module of degree 3 and rank 3 over Integer Ring
            Echelon basis matrix:
            [1 0 0]
            [0 3 0]
            [0 0 9]
        """
        return self._module_rep

    def intersection(self, other):
        """
        Return the intersection of this order with another order.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: k.<i> = NumberField(x^2 + 1)
            sage: O6 = k.order(6*i)
            sage: O9 = k.order(9*i)
            sage: O6.basis()
            [1, 6*i]
            sage: O9.basis()
            [1, 9*i]
            sage: O6.intersection(O9).basis()
            [1, 18*i]
            sage: (O6 & O9).basis()
            [1, 18*i]
            sage: (O6 + O9).basis()
            [1, 3*i]
        """
        return self & other

    def _repr_(self):
        """
        Return print representation of this absolute order.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^4 - 5)
            sage: K.maximal_order()._repr_()
            'Maximal Order generated by [1/2*a^2 + 1/2, 1/2*a^3 + 1/2*a] in Number Field in a with defining polynomial x^4 - 5'
            sage: K.order(a)._repr_()
            'Order generated by a in Number Field in a with defining polynomial x^4 - 5'

        We have special cases for Gaussian and Eisenstein integers::

            sage: K = CyclotomicField(4)
            sage: K.ring_of_integers()
            Gaussian Integers generated by zeta4 in Cyclotomic Field of order 4 and degree 2
            sage: K = QuadraticField(-3)
            sage: K.ring_of_integers()
            Eisenstein Integers generated by 1/2*a + 1/2 in Number Field in a with defining polynomial x^2 + 3 with a = 1.732050807568878?*I
        """
        if self._is_maximal():
            s = "Maximal Order"
            if self.degree() == 2:
                D = self.discriminant()
                if D == -3:
                    s = "Eisenstein Integers"
                if D == -4:
                    s = "Gaussian Integers"
        else:
            s = "Order"
            if self.number_field().absolute_degree() == 2:
                f = self.conductor()
                s += f' of conductor {f}'
        try:
            gens = self.ring_generators()
        except TypeError:
            gens = self.gens()
        s += f' generated by {gens[0] if len(gens) == 1 else "[" + ", ".join(map(str, gens)) + "]"}'
        s += f' in {self._K}'
        return s

    def basis(self):
        r"""
        Return the basis over `\ZZ` for this order.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: k.<c> = NumberField(x^3 + x^2 + 1)
            sage: O = k.maximal_order(); O
            Maximal Order generated by c in Number Field in c with defining polynomial x^3 + x^2 + 1
            sage: O.basis()
            [1, c, c^2]

        The basis is an immutable sequence::

            sage: type(O.basis())
            <class 'sage.structure.sequence.Sequence_generic'>

        The generator functionality uses the basis method::

            sage: O.0
            1
            sage: O.1
            c
            sage: O.basis()
            [1, c, c^2]
            sage: O.ngens()
            3
        """
        try:
            return self.__basis
        except AttributeError:
            V, from_V, to_V = self._K.vector_space()
            B = Sequence([self(from_V(b)) for b in self._module_rep.basis()], immutable=True)
            self.__basis = B
        return B

    def absolute_order(self):
        """
        Return the absolute order associated to this order, which is
        just this order again since this is an absolute order.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a> = NumberField(x^3 + 2)
            sage: O1 = K.order(a); O1
            Maximal Order generated by a in Number Field in a with defining polynomial x^3 + 2
            sage: O1.absolute_order() is O1
            True
        """
        return self


class Order_relative(Order):
    """
    A relative order in a number field.

    A relative order is an order in some relative number field.

    Invariants of this order may be computed with respect to the
    contained order.
    """

    def __init__(self, K, absolute_order):
        """
        Create the relative order.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: k.<a,b> = NumberFieldTower([x^2 - 3, x^2 + 1])
            sage: O = k.maximal_order(); O # indirect doctest
            Maximal Relative Order generated by 1/2*a - 1/2*b in Number Field in a with defining polynomial x^2 - 3 over its base field

            sage: _ = O.basis()

        TESTS::

            sage: loads(dumps(O)) is O
            True
            sage: TestSuite(O).run()
        """
        self._absolute_order = absolute_order
        self._module_rep = absolute_order._module_rep

        Order.__init__(self, K)

    def _element_constructor_(self, x):
        """
        Coerce an element into this relative order.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a, b> = NumberField([x^2 + 2, x^2 + 1000*x + 1])
            sage: OK = K.ring_of_integers()
            sage: OK(a)
            a
            sage: OK([3, 4])
            4*a + 3

        The following used to fail; see :issue:`5276`::

            sage: S.<y> = OK[]; S
            Univariate Polynomial Ring in y over Maximal Relative Order generated by [(-5787/2*b - 9/2)*a - 964565*b - 965, (-1500*b - 2)*a - 499997*b - 500] in Number Field in a with defining polynomial x^2 + 2 over its base field

        We test that :issue:`4193` is also fixed::

            sage: K1.<a> = NumberField(x^3 - 2)
            sage: R.<y> = PolynomialRing(K1)
            sage: K2.<b> = K1.extension(y^2 - a)
            sage: R = K2.order(b)
            sage: b in R
            True
            sage: bb = R.basis()[1]  # b by any other name
            sage: bb == b
            True
            sage: bb.parent() is R
            True
            sage: bb in R # this used to return False
            True
            sage: R(bb) == bb # this used to raise an error
            True
        """

        x = self._K(x)
        abs_order = self._absolute_order
        to_abs = abs_order._K.structure()[1]
        x = abs_order(to_abs(x))  # will test membership
        return OrderElement_relative(self, x)

    def _repr_(self):
        """
        Return print representation of this relative order.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: O = EquationOrder([x^2 + x + 1, x^3 - 2],'a,b')
            sage: O._repr_()
            'Relative Order generated by [(-b^2 + 6*b + 11)*a + 3*b^2 + b + 14, (-2*b^2 - 2)*a - 2*b^2 - b, (b + 6)*a + 3*b^2 + 6] in Number Field in a with defining polynomial x^2 + x + 1 over its base field'
        """
        s = 'Maximal ' if self._is_maximal() else ''
        s += 'Relative Order'
        try:
            gens = self.ring_generators()
        except TypeError:
            gens = self.gens()
        s += f' generated by {gens[0] if len(gens) == 1 else "[" + ", ".join(map(str, gens)) + "]"}'
        s += f' in {self._K}'
        return s

    def absolute_order(self, names='z'):
        """
        Return underlying absolute order associated to this relative
        order.

        INPUT:

        - ``names`` -- string (default: ``'z'``); name of generator of absolute
          extension

        .. NOTE::

           There *is* a default variable name, since this absolute
           order is frequently used for internal algorithms.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: R = EquationOrder([x^2 + 1, x^2 - 5], 'i,g'); R
            Relative Order generated by [6*i - g, -g*i + 2, 7*i - g] in
             Number Field in i with defining polynomial x^2 + 1 over its base field
            sage: R.basis()
            [1, 6*i - g, -g*i + 2, 7*i - g]

            sage: S = R.absolute_order(); S
            Order generated by [5/12*z^3 + 1/6*z, 1/2*z^2, 1/2*z^3] in Number Field in z with defining polynomial x^4 - 8*x^2 + 36
            sage: S.basis()
            [1, 5/12*z^3 + 1/6*z, 1/2*z^2, 1/2*z^3]

        We compute a relative order in alpha0, alpha1, then make the
        generator of the number field that contains the absolute order be called
        gamma.::

            sage: R = EquationOrder( [x^2 + 2, x^2 - 3], 'alpha'); R
            Relative Order generated by [-alpha1*alpha0 + 1, 5*alpha0 + 2*alpha1, 7*alpha0 + 3*alpha1] in
             Number Field in alpha0 with defining polynomial x^2 + 2 over its base field
            sage: R.absolute_order('gamma')
            Order generated by [1/2*gamma^2 + 1/2, 7/10*gamma^3 + 1/10*gamma, gamma^3] in Number Field in gamma with defining polynomial x^4 - 2*x^2 + 25
            sage: R.absolute_order('gamma').basis()
            [1/2*gamma^2 + 1/2, 7/10*gamma^3 + 1/10*gamma, gamma^2, gamma^3]
        """
        if names == 'z' or names == ('z',):
            return self._absolute_order
        else:
            return self._absolute_order.change_names(names)

    def basis(self):
        r"""
        Return a basis for this order as `\ZZ`-module.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a,b> = NumberField([x^2 + 1, x^2 + 3])
            sage: O = K.order([a,b])
            sage: O.basis()
            [1, -2*a + b, -b*a - 2, -5*a + 3*b]
            sage: z = O.1; z
            -2*a + b
            sage: z.absolute_minpoly()
            x^4 + 14*x^2 + 1
        """
        try:
            return self.__basis
        except AttributeError:
            pass
        O = self._absolute_order
        K = O.number_field()
        from_K, _ = K.structure()
        self.__basis = [OrderElement_relative(self, from_K(a)) for a in O.basis()]
        return self.__basis

    def __add__(left, right):
        """
        Add two relative orders or a relative order to an absolute
        order (which always results in an absolute order).

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a,b> = NumberField([x^2 + 1, x^2 + 3])
            sage: O2 = K.order([2*a, b]); O2.absolute_discriminant()
            36864
            sage: O3 = K.order([3*a, 2*b]); O3.absolute_discriminant()
            2985984
            sage: R = O2 + O3; R
            Relative Order generated by [-2*a + b, -2*b*a - 4, -5*a + 3*b] in Number Field in a with defining polynomial x^2 + 1 over its base field
            sage: R.absolute_discriminant()
            9216
            sage: R.is_suborder(O2)
            False
            sage: O2.is_suborder(R)
            True
            sage: O3.is_suborder(R)
            True
        """
        if isinstance(right, Order_absolute):
            return left._absolute_order + right

        if not isinstance(right, Order_relative):
            raise NotImplementedError("cannot add these orders yet")

        if left._K != right._K:
            raise TypeError("number fields do not match")

        if left._is_maximal():
            return left

        if right._is_maximal():
            return right

        return RelativeOrder(left._K, left._absolute_order + right._absolute_order, check=False)

    def __and__(left, right):
        """
        Intersect two relative orders or a relative and absolute order
        (which always results in an absolute order).

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: L.<a, b> = NumberField([x^2 + 1, x^2 - 5])
            sage: O1 = L.order([a, 2*b])
            sage: O2 = L.order([2*a, b])
            sage: O3 = O1 & O2; O3
            Relative Order generated by [12*a - 2*b, -2*b*a + 4, 14*a - 2*b] in Number Field in a with defining polynomial x^2 + 1 over its base field
            sage: O3.index_in(L.maximal_order())
            32

        TESTS:

        Verify that :issue:`33386` has been resolved::

            sage: (L.maximal_order() & L.maximal_order()).is_maximal()
            True
        """
        if isinstance(right, Order_absolute):
            return left._absolute_order & right

        if not isinstance(right, Order_relative):
            raise NotImplementedError("cannot intersect these orders yet")

        if left._K != right._K:
            raise TypeError("number fields do not match")

        return RelativeOrder(left._K, left._absolute_order & right._absolute_order, check=False)

    def is_maximal(self, p=None):
        """
        Return whether this is the maximal order.

        INPUT:

        - ``p`` -- integer prime or ``None`` (default: ``None``); if
          set, return whether this order is maximal at the prime `p`

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a, b> = NumberField([x^2 + 1, x^2 - 5])

            sage: K.order(3*a, b).is_maximal()
            False
            sage: K.order(5*a, b/2 + 1/2).is_maximal()
            False
            sage: (K.order(3*a, b) + K.order(5*a, b/2 + 1/2)).is_maximal()
            True
            sage: K.maximal_order().is_maximal()
            True

        Maximality can be checked at primes when the order is maximal at that
        prime by construction::

            sage: K.maximal_order().is_maximal(p=3)
            True

        And at other primes::

            sage: K.order(3*a, b).is_maximal(p=3)
            False
        """
        return self._absolute_order.is_maximal(p=p)

    def _is_maximal(self):
        r"""
        Return whether this order is already known to be maximal.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a, b> = NumberField([x^2 + 1, x^2 - 5])
            sage: O = K.order(a, b)
            sage: O._is_maximal() is None
            True
            sage: O.is_maximal()
            False
            sage: O._is_maximal()
            False
        """
        return self._absolute_order._is_maximal()

    def _is_maximal_at(self, p=None):
        r"""
        Return whether this order is already known to be maximal at ``p``.

        When no ``p`` is specified, returns a dictionary of primes for which
        maximality is known.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a, b> = NumberField([x^2 - 2, x^13 - 2])
            sage: O = K.maximal_order([2, 3, 5], assume_maximal=None)
            sage: O._is_maximal_at(p=7) is None
            True
            sage: O = K.maximal_order([2, 3, 7], assume_maximal=None)
            sage: O._is_maximal_at(p=5)
            True
            sage: O._is_maximal_at(p=7)
            True
            sage: O._is_maximal_at()
            {2: True, 3: True, 5: True, 7: True}
        """
        return self._absolute_order._is_maximal_at(p=p)

    def _assume_maximal(self, is_maximal=True, p=None):
        r"""
        Record that this order ``is_maximal`` at the integer prime ``p``.

        To support the deprecated behavior for
        ``is_maximal="non-maximal-non-unique"``, this returns an order.
        Typically, the order itself.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: L.<a, b> = NumberField([x^2 - 1000005, x^2 - 5*1000099^2])
            sage: O = L.maximal_order([13], assume_maximal=None)

        We can store information about more primes::

            sage: O._is_maximal_at(p=7) is None
            True
            sage: 7.divides(L.absolute_discriminant())
            False
            sage: O._assume_maximal(p=7) is O
            True
            sage: O._is_maximal_at(p=7)
            True

        We cannot store contradicting information at a prime::

            sage: O._assume_maximal(p=7, is_maximal=False)
            Traceback (most recent call last):
            ...
            ValueError: cannot assume this order to be non-maximal at 7 because we already found it to be maximal at that prime

        We can safely store information that we know to be wrong to support
        legacy behavior of orders that are assumed to be only maximal at some
        primes::

            sage: L.<a, b> = NumberField([x^2 - 2, x^3 - 2])
            sage: O = L.maximal_order([2, 3], assume_maximal=None)
            sage: O.is_maximal()
            True
            sage: N = O._assume_maximal(is_maximal='non-maximal-non-unique')
            sage: N._assume_maximal(p=2) is N
            True
            sage: N is O
            False
            sage: N == O
            True
            sage: N.is_maximal()
            False
            sage: N.is_maximal(p=2)
            True
        """
        absolute_order = self._absolute_order._assume_maximal(is_maximal=is_maximal, p=p)
        if absolute_order is not self._absolute_order:
            assert is_maximal == "non-maximal-non-unique"
            self = type(self)(self._K, absolute_order)
        return self

    def absolute_discriminant(self):
        """
        Return the absolute discriminant of ``self``, which is the discriminant
        of the absolute order associated to ``self``.

        OUTPUT: integer

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: R = EquationOrder([x^2 + 1, x^3 + 2], 'a,b')
            sage: d = R.absolute_discriminant(); d
            -746496
            sage: d is R.absolute_discriminant()
            True
            sage: factor(d)
            -1 * 2^10 * 3^6
        """
        return self.absolute_order().discriminant()

    def is_suborder(self, other):
        """
        Return ``True`` if ``self`` is a subset of the order ``other``.

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a,b> = NumberField([x^2 + 1, x^3 + 2])
            sage: R1 = K.order([a, b])
            sage: R2 = K.order([2*a, b])
            sage: R3 = K.order([a + b, b + 2*a])
            sage: R1.is_suborder(R2)
            False
            sage: R2.is_suborder(R1)
            True
            sage: R3.is_suborder(R1)
            True
            sage: R1.is_suborder(R3)
            True
            sage: R1 == R3
            True
        """
        return self.absolute_order().is_suborder(other.absolute_order())

    def index_in(self, other):
        """
        Return the index of ``self`` in ``other``.

        This is a lattice index,
        so it is a rational number if ``self`` is not contained in ``other``.

        INPUT:

        - ``other`` -- another order with the same ambient absolute number field

        OUTPUT: a rational number

        EXAMPLES::

            sage: x = polygen(ZZ, 'x')
            sage: K.<a,b> = NumberField([x^3 + x + 3, x^2 + 1])
            sage: R1 = K.order([3*a, 2*b])
            sage: R2 = K.order([a, 4*b])
            sage: R1.index_in(R2)
            729/8
            sage: R2.index_in(R1)
            8/729
        """
        if not isinstance(other, Order):
            raise TypeError("other must be an absolute order.")
        return self.absolute_order().index_in(other.absolute_order())


def each_is_integral(v):
    """
    Return whether every element of the list ``v`` of elements of a number
    field is integral.

    EXAMPLES::

        sage: x = polygen(ZZ, 'x')
        sage: W.<sqrt5> = NumberField(x^2 - 5)
        sage: from sage.rings.number_field.order import each_is_integral
        sage: each_is_integral([sqrt5, 2, (1+sqrt5)/2])
        True
        sage: each_is_integral([sqrt5, (1+sqrt5)/3])
        False
    """
    return all(x.is_integral() for x in v)


def absolute_order_from_ring_generators(gens, check_is_integral=True,
                                        check_rank=True, is_maximal=None,
                                        allow_subfield=False):
    """
    INPUT:

    - ``gens`` -- list of integral elements of an absolute order
    - ``check_is_integral`` -- boolean (default: ``True``); whether to check
      that each generator is integral
    - ``check_rank`` -- boolean (default: ``True``); whether to check that the
      ring generated by ``gens`` is of full rank
    - ``is_maximal`` -- boolean (or ``None``); set if maximality of the
      generated order is known
    - ``allow_subfield`` -- boolean (default: ``False``); if ``True`` and the
      generators do not generate an order, i.e., they generate a subring of
      smaller rank, instead of raising an error, return an order in a smaller
      number field

    EXAMPLES::

        sage: x = polygen(ZZ, 'x')
        sage: K.<a> = NumberField(x^4 - 5)
        sage: K.order(a)
        Order generated by a in Number Field in a with defining polynomial x^4 - 5

    We have to explicitly import this function, since typically it is called
    with ``K.order`` as above.::

        sage: from sage.rings.number_field.order import absolute_order_from_ring_generators
        sage: absolute_order_from_ring_generators([a])
        Order generated by a in Number Field in a with defining polynomial x^4 - 5
        sage: absolute_order_from_ring_generators([3*a, 2, 6*a + 1])
        Order generated by 3*a in Number Field in a with defining polynomial x^4 - 5

    If one of the inputs is non-integral, it is an error.::

        sage: absolute_order_from_ring_generators([a/2])
        Traceback (most recent call last):
        ...
        ValueError: each generator must be integral

    If the ``gens`` do not generate an order, i.e., generate a ring of full
    rank, then it is an error.::

        sage: absolute_order_from_ring_generators([a^2])
        Traceback (most recent call last):
        ...
        ValueError: the rank of the span of gens is wrong

    Both checking for integrality and checking for full rank can be
    turned off in order to save time, though one can get nonsense as
    illustrated below.::

        sage: absolute_order_from_ring_generators([a/2], check_is_integral=False)
        Order generated by [1, 1/2*a, 1/4*a^2, 1/8*a^3] in Number Field in a with defining polynomial x^4 - 5
        sage: absolute_order_from_ring_generators([a^2], check_rank=False)
        Order generated by a^2 in Number Field in a with defining polynomial x^4 - 5
    """
    if check_is_integral and not each_is_integral(gens):
        raise ValueError("each generator must be integral")
    gens = Sequence(gens)
    n = [x.absolute_minpoly().degree() for x in gens]
    module_gens = monomials(gens, n)
    return absolute_order_from_module_generators(module_gens,
                                                 check_integral=False,
                                                 check_is_ring=False,
                                                 check_rank=check_rank,
                                                 is_maximal=is_maximal,
                                                 allow_subfield=allow_subfield)


def absolute_order_from_module_generators(gens,
                                          check_integral=True, check_rank=True,
                                          check_is_ring=True, is_maximal=None,
                                          allow_subfield=False, is_maximal_at=()):
    r"""
    INPUT:

    - ``gens`` -- list of elements of an absolute number field that generates an
      order in that number field as a `\ZZ`-*module*
    - ``check_integral`` -- check that each generator is integral
    - ``check_rank`` -- check that the ``gens`` span a module of the correct
      rank
    - ``check_is_ring`` -- check that the module is closed under multiplication
      (this is very expensive)
    - ``is_maximal`` -- boolean (or ``None``); set if maximality of the
      generated order is known
    - ``is_maximal_at`` -- tuple of primes where this order is known to be
      maximal

    OUTPUT: an absolute order

    EXAMPLES:

    We have to explicitly import the function, since it is not meant
    for regular usage::

        sage: from sage.rings.number_field.order import absolute_order_from_module_generators

        sage: x = polygen(ZZ, 'x')
        sage: K.<a> = NumberField(x^4 - 5)
        sage: O = K.maximal_order(); O
        Maximal Order generated by [1/2*a^2 + 1/2, 1/2*a^3 + 1/2*a] in Number Field in a with defining polynomial x^4 - 5
        sage: O.basis()
        [1/2*a^2 + 1/2, 1/2*a^3 + 1/2*a, a^2, a^3]
        sage: O.module()
        Free module of degree 4 and rank 4 over Integer Ring
        Echelon basis matrix:
        [1/2   0 1/2   0]
        [  0 1/2   0 1/2]
        [  0   0   1   0]
        [  0   0   0   1]
        sage: g = O.basis(); g
        [1/2*a^2 + 1/2, 1/2*a^3 + 1/2*a, a^2, a^3]
        sage: absolute_order_from_module_generators(g)
        Maximal Order generated by [1/2*a^2 + 1/2, 1/2*a^3 + 1/2*a] in Number Field in a with defining polynomial x^4 - 5

    We illustrate each check flag -- the output is the same but in case
    the function would run ever so slightly faster::

        sage: absolute_order_from_module_generators(g,  check_is_ring=False)
        Maximal Order generated by [1/2*a^2 + 1/2, 1/2*a^3 + 1/2*a] in Number Field in a with defining polynomial x^4 - 5
        sage: absolute_order_from_module_generators(g,  check_rank=False)
        Maximal Order generated by [1/2*a^2 + 1/2, 1/2*a^3 + 1/2*a] in Number Field in a with defining polynomial x^4 - 5
        sage: absolute_order_from_module_generators(g,  check_integral=False)
        Maximal Order generated by [1/2*a^2 + 1/2, 1/2*a^3 + 1/2*a] in Number Field in a with defining polynomial x^4 - 5

    Next we illustrate constructing "fake" orders to illustrate turning
    off various check flags::

        sage: k.<i> = NumberField(x^2 + 1)
        sage: R = absolute_order_from_module_generators([2, 2*i],
        ....:                                           check_is_ring=False); R
        Order of conductor 4 generated by [2, 2*i]
         in Number Field in i with defining polynomial x^2 + 1
        sage: R.basis()
        [2, 2*i]
        sage: R = absolute_order_from_module_generators([k(1)],                         # needs sage.symbolic
        ....:                                           check_rank=False); R
        Order of conductor I generated by []
         in Number Field in i with defining polynomial x^2 + 1
        sage: R.basis()                                                                 # needs sage.symbolic
        [1]

    If the order contains a non-integral element, even if we do not check
    that, we will find that the rank is wrong or that the order is not closed
    under multiplication::

        sage: absolute_order_from_module_generators([1/2, i],
        ....:                                       check_integral=False)
        Traceback (most recent call last):
        ...
        ValueError: the module span of the gens is not closed under multiplication.
        sage: R = absolute_order_from_module_generators([1/2, i],
        ....:                                           check_is_ring=False,
        ....:                                           check_integral=False); R
        Order of conductor 0 generated by [1/2, i] in Number Field in i with defining polynomial x^2 + 1
        sage: R.basis()
        [1/2, i]

    We turn off all check flags and make a really messed up order::

        sage: R = absolute_order_from_module_generators([1/2, i],
        ....:                                           check_is_ring=False,
        ....:                                           check_integral=False,
        ....:                                           check_rank=False); R
        Order of conductor 0 generated by [1/2, i] in Number Field in i with defining polynomial x^2 + 1
        sage: R.basis()
        [1/2, i]

    An order that lives in a subfield::

        sage: F.<alpha> = NumberField(x**4 + 3)
        sage: F.order([alpha**2], allow_subfield=True)
        Order of conductor 2 generated by ... in Number Field in beta with defining polynomial ... with beta = ...
    """
    if not gens:
        raise ValueError("gens must span an order over ZZ")
    gens = Sequence(gens)
    if check_integral and not each_is_integral(gens):
        raise ValueError("each generator must be integral")

    K = gens.universe()
    if isinstance(K, Order) or K == ZZ:
        K = K.number_field()
    V, from_V, to_V = K.vector_space()
    mod_gens = [to_V(x) for x in gens]
    ambient = ZZ**V.dimension()
    W = ambient.span(mod_gens)

    if allow_subfield:
        if W.rank() < K.degree():
            # We have to make the order in a smaller field.
            # We do this by choosing a random element of W,
            # moving it back to K, and checking that it defines
            # a field of degree equal to the degree of W.
            # Then we move everything into that field, where
            # W does define an order.
            while True:
                alpha = from_V(W.random_element())
                if alpha.minpoly().degree() == W.rank():
                    break
            # Now alpha generates a subfield where W is an order
            # (with the right rank).
            # We move each generator of W to this subfield.
            K, _ = K.subfield(alpha, 'beta')
            gens = [K(x) for x in gens]
            V, from_V, to_V = K.vector_space()
            mod_gens = [to_V(x) for x in gens]
            ambient = ZZ**V.dimension()
            W = ambient.span(mod_gens)

    elif check_rank:
        if W.rank() != K.degree():
            raise ValueError("the rank of the span of gens is wrong")

    if check_is_ring:
        if any(to_V(x * y) not in W for x in gens for y in gens):
            raise ValueError("the module span of the gens is not closed under multiplication.")

    return AbsoluteOrder(K, W, check=False, is_maximal=is_maximal, is_maximal_at=is_maximal_at)


def relative_order_from_ring_generators(gens,
                                        check_is_integral=True,
                                        check_rank=True,
                                        is_maximal=None,
                                        allow_subfield=False,
                                        is_maximal_at=()):
    """
    INPUT:

    - ``gens`` -- list of integral elements of an absolute order
    - ``check_is_integral`` -- boolean (default: ``True``); whether to check
      that each generator is integral
    - ``check_rank`` -- boolean (default: ``True``); whether to check that the
      ring generated by ``gens`` is of full rank
    - ``is_maximal`` -- boolean (or ``None``); set if maximality of the
      generated order is known

    EXAMPLES:

    We have to explicitly import this function, since it is not meant
    for regular usage::

        sage: from sage.rings.number_field.order import relative_order_from_ring_generators
        sage: x = polygen(ZZ, 'x')
        sage: K.<i, a> = NumberField([x^2 + 1, x^2 - 17])
        sage: R = K.base_field().maximal_order()
        sage: S = relative_order_from_ring_generators([i,a]); S
        Relative Order generated by [7*i - 2*a, -a*i + 8, 25*i - 7*a] in
         Number Field in i with defining polynomial x^2 + 1 over its base field

    Basis for the relative order, which is obtained by computing the algebra generated
    by i and a::

        sage: S.basis()
        [1, 7*i - 2*a, -a*i + 8, 25*i - 7*a]
    """
    if check_is_integral and not each_is_integral(gens):
        raise ValueError("each generator must be integral")
    gens = Sequence(gens)

    # The top number field that contains the order.
    K = gens.universe()

    # The absolute version of that field.
    Kabs = K.absolute_field('z')
    from_Kabs, to_Kabs = Kabs.structure()

    module_gens = [to_Kabs(a) for a in gens]
    n = [a.absolute_minpoly().degree() for a in gens]
    absolute_order_module_gens = monomials(module_gens, n)

    abs_order = absolute_order_from_module_generators(absolute_order_module_gens,
                                                      check_integral=False,
                                                      check_is_ring=False,
                                                      check_rank=check_rank,
                                                      is_maximal=is_maximal,
                                                      is_maximal_at=is_maximal_at)

    return RelativeOrder(K, abs_order, check=False)


def GaussianIntegers(names='I', latex_name='i'):
    r"""
    Return the ring of Gaussian integers.

    This is the ring of all complex numbers
    of the form `a + b I` with `a` and `b` integers and `I = \sqrt{-1}`.

    EXAMPLES::

        sage: ZZI.<I> = GaussianIntegers()
        sage: ZZI
        Gaussian Integers generated by I in Number Field in I with defining polynomial x^2 + 1 with I = 1*I
        sage: factor(3 + I)
        (-2*I - 1) * (I - 1)
        sage: CC(I)
        1.00000000000000*I
        sage: I.minpoly()
        x^2 + 1
        sage: GaussianIntegers().basis()
        [1, I]
    """
    from sage.rings.complex_double import CDF
    from sage.rings.number_field.number_field import NumberField
    f = ZZ['x']([1, 0, 1])
    nf = NumberField(f, names, embedding=CDF(0, 1), latex_name=latex_name)
    return nf.ring_of_integers()


def EisensteinIntegers(names='omega'):
    r"""
    Return the ring of Eisenstein integers.

    This is the ring of all complex numbers
    of the form `a + b \omega` with `a` and `b` integers and
    `\omega = (-1 + \sqrt{-3})/2`.

    EXAMPLES::

        sage: R.<omega> = EisensteinIntegers()
        sage: R
        Eisenstein Integers generated by omega in Number Field in omega
         with defining polynomial x^2 + x + 1
         with omega = -0.50000000000000000? + 0.866025403784439?*I
        sage: factor(3 + omega)
        (omega) * (-3*omega - 2)
        sage: CC(omega)
        -0.500000000000000 + 0.866025403784439*I
        sage: omega.minpoly()
        x^2 + x + 1
        sage: EisensteinIntegers().basis()
        [1, omega]
    """
    from sage.rings.complex_double import CDF
    from sage.rings.number_field.number_field import NumberField
    f = ZZ['x']([1, 1, 1])
    nf = NumberField(f, names, embedding=CDF(-0.5, 0.8660254037844386))
    return nf.ring_of_integers()
