Esempio n. 1
0
    def __init__(self, degree, base_ring, category=None):
        """
        Base class for matrix groups over generic base rings

        You should not use this class directly. Instead, use one of
        the more specialized derived classes.

        INPUT:

        - ``degree`` -- integer. The degree (matrix size) of the
          matrix group.

        - ``base_ring`` -- ring. The base ring of the matrices.

        TESTS::

            sage: G = GL(2, QQ)
            sage: from sage.groups.matrix_gps.matrix_group import MatrixGroup_generic
            sage: isinstance(G, MatrixGroup_generic)
            True
        """
        assert is_Ring(base_ring)
        assert is_Integer(degree)

        self._deg = degree
        if self._deg <= 0:
            raise ValueError('the degree must be at least 1')

        if (category is None) and is_FiniteField(base_ring):
            from sage.categories.finite_groups import FiniteGroups
            category = FiniteGroups()
        super(MatrixGroup_generic, self).__init__(base=base_ring, category=category)
Esempio n. 2
0
    def create_key(self,
                   coeff_ring=ZZ,
                   group='Sp(4,Z)',
                   weights='even',
                   degree=2,
                   default_prec=SMF_DEFAULT_PREC):
        """
        Create a key which uniquely defines this algebra of Siegel modular 
        forms.

        TESTS::

            sage: SiegelModularFormsAlgebra.create_key(coeff_ring=QQ, group='Gamma0(5)', weights='all', degree=2, default_prec=41)
            (SMFAlg{"Gamma0(5)", "all", 2, 41}(FractionField(...)), Integer Ring)
        """
        from sage.rings.ring import is_Ring
        if not is_Ring(coeff_ring):
            raise TypeError('The coefficient ring must be a ring')
        if not (isinstance(group, str) or group is None):
            raise TypeError('The group must be given by a string, or None')
        if not weights in ('even', 'all'):
            raise ValueError("The argument weights must be 'even' or 'all'")
        try:
            degree = int(degree)
        except TypeError:
            raise TypeError('The degree must be a positive integer')
        if degree < 1:
            raise ValueError('The degree must be a positive integer')
        if degree == 1:
            raise ValueError(
                'Use ModularForms if you want to work with Siegel modular forms of degree 1'
            )
        if degree > 2:
            raise NotImplementedError(
                'Siegel modular forms of degree > 2 are not yet implemented')
        try:
            default_prec = int(default_prec)
        except TypeError:
            raise TypeError('The default precision must be a positive integer')

        from .pushout import SiegelModularFormsAlgebraFunctor
        F = SiegelModularFormsAlgebraFunctor(group=group,
                                             weights=weights,
                                             degree=degree,
                                             default_prec=default_prec)

        while hasattr(coeff_ring, 'construction'):
            C = coeff_ring.construction()
            if C is None:
                break
            F = F * C[0]
            coeff_ring = C[1]
        return (F, coeff_ring)
Esempio n. 3
0
    def _coerce_map_from_(self, S):
        r"""
        True if there is a coercion from ``S`` to ``self``, False otherwise.
        The actual coercion is done by the :meth:`_element_constructor_`
        method.

        INPUT:

        -  ``S`` - a Sage object.

        The objects that coerce into a group algebra `k[G]` are:

        - any group algebra `R[H]` as long as `R` coerces into `k` and
          `H` coerces into `G`.

        - any ring `R` which coerces into `k`

        - any group `H` which coerces into either `k` or `G`.

        Note that if `H` is a group which coerces into both `k` and
        `G`, then Sage will always use the map to `k`.  For example,
        if `\ZZ` is the ring (or group) of integers, then `\ZZ` will
        coerce to any `k[G]`, by sending `\ZZ` to `k`.

        EXAMPLES::

            sage: A = GroupAlgebra(SymmetricGroup(4), QQ)
            sage: B = GroupAlgebra(SymmetricGroup(3), ZZ)
            sage: A._coerce_map_from_(B)
            True
            sage: B._coerce_map_from_(A)
            False
            sage: A._coerce_map_from_(ZZ)
            True
            sage: A._coerce_map_from_(CC)
            False
            sage: A._coerce_map_from_(SymmetricGroup(5))
            False
            sage: A._coerce_map_from_(SymmetricGroup(2))
            True
        """
        from sage.rings.ring import is_Ring
        from sage.groups.old import Group
        k = self.base_ring()
        G = self.group()
        if isinstance(S, GroupAlgebra):
            return (k.has_coerce_map_from(S.base_ring())
                    and G.has_coerce_map_from(S.group()))
        if is_Ring(S):
            return k.has_coerce_map_from(S)
        if isinstance(S, Group):
            return k.has_coerce_map_from(S) or G.has_coerce_map_from(S)
Esempio n. 4
0
    def _coerce_map_from_(self, S):
        r"""
        True if there is a coercion from ``S`` to ``self``, False otherwise.
        The actual coercion is done by the :meth:`_element_constructor_`
        method.

        INPUT:

        -  ``S`` - a Sage object.

        The objects that coerce into a group algebra `k[G]` are:

        - any group algebra `R[H]` as long as `R` coerces into `k` and
          `H` coerces into `G`.

        - any ring `R` which coerces into `k`

        - any group `H` which coerces into either `k` or `G`.

        Note that if `H` is a group which coerces into both `k` and
        `G`, then Sage will always use the map to `k`.  For example,
        if `\ZZ` is the ring (or group) of integers, then `\ZZ` will
        coerce to any `k[G]`, by sending `\ZZ` to `k`.

        EXAMPLES::

            sage: A = GroupAlgebra(SymmetricGroup(4), QQ)
            sage: B = GroupAlgebra(SymmetricGroup(3), ZZ)
            sage: A._coerce_map_from_(B)
            True
            sage: B._coerce_map_from_(A)
            False
            sage: A._coerce_map_from_(ZZ)
            True
            sage: A._coerce_map_from_(CC)
            False
            sage: A._coerce_map_from_(SymmetricGroup(5))
            False
            sage: A._coerce_map_from_(SymmetricGroup(2))
            True
        """
        from sage.rings.ring import is_Ring
        from sage.groups.old import Group
        k = self.base_ring()
        G = self.group()
        if isinstance(S, GroupAlgebra):
            return (k.has_coerce_map_from(S.base_ring())
                    and G.has_coerce_map_from(S.group()))
        if is_Ring(S):
            return k.has_coerce_map_from(S)
        if isinstance(S,Group):
            return k.has_coerce_map_from(S) or G.has_coerce_map_from(S)
Esempio n. 5
0
    def base_change_to(self, R):
        """
        Alters the quadratic form to have all coefficients
        defined over the new base_ring R.  Here R must be
        coercible to from the current base ring.

        Note: This is preferable to performing an explicit
        coercion through the base_ring() method, which does
        not affect the individual coefficients.  This is
        particularly useful for performing fast modular
        arithmetic evaluations.

        INPUT:
            R -- a ring

        OUTPUT:
            quadratic form

        EXAMPLES::

            sage: Q = DiagonalQuadraticForm(ZZ,[1,1]); Q
            Quadratic form in 2 variables over Integer Ring with coefficients:
            [ 1 0 ]
            [ * 1 ]

        ::

            sage: Q1 = Q.base_change_to(IntegerModRing(5)); Q1
            Quadratic form in 2 variables over Ring of integers modulo 5 with coefficients:
            [ 1 0 ]
            [ * 1 ]

            sage: Q1([35,11])
            1

        """
        ## Check that a canonical coercion is possible
        if not is_Ring(R):
            raise TypeError, "Oops!  R is not a ring. =("
        if not R.has_coerce_map_from(self.base_ring()):
            raise TypeError, "Oops!  There is no canonical coercion from " + str(
                self.base_ring()) + " to R."

        ## Return the coerced form
        return QuadraticForm(R, self.dim(),
                             [R(x) for x in self.coefficients()])
Esempio n. 6
0
    def base_change_to(self, R):
        """
        Alters the quadratic form to have all coefficients
        defined over the new base_ring R.  Here R must be
        coercible to from the current base ring.

        Note: This is preferable to performing an explicit
        coercion through the base_ring() method, which does
        not affect the individual coefficients.  This is
        particularly useful for performing fast modular
        arithmetic evaluations.

        INPUT:
            R -- a ring

        OUTPUT:
            quadratic form

        EXAMPLES::

            sage: Q = DiagonalQuadraticForm(ZZ,[1,1]); Q
            Quadratic form in 2 variables over Integer Ring with coefficients:
            [ 1 0 ]
            [ * 1 ]

        ::

            sage: Q1 = Q.base_change_to(IntegerModRing(5)); Q1
            Quadratic form in 2 variables over Ring of integers modulo 5 with coefficients:
            [ 1 0 ]
            [ * 1 ]

            sage: Q1([35,11])
            1

        """
        ## Check that a canonical coercion is possible
        if not is_Ring(R):
            raise TypeError("Oops!  R is not a ring. =(")
        if not R.has_coerce_map_from(self.base_ring()):
            raise TypeError("Oops!  There is no canonical coercion from " + str(self.base_ring()) + " to R.")

        ## Return the coerced form
        return QuadraticForm(R, self.dim(), [R(x) for x in self.coefficients()])
    def create_key(self, coeff_ring=ZZ, group='Sp(4,Z)', weights='even', degree=2, default_prec=SMF_DEFAULT_PREC):
        """
        Create a key which uniquely defines this algebra of Siegel modular 
        forms.

        TESTS::

            sage: SiegelModularFormsAlgebra.create_key(coeff_ring=QQ, group='Gamma0(5)', weights='all', degree=2, default_prec=41)
            (SMFAlg{"Gamma0(5)", "all", 2, 41}(FractionField(...)), Integer Ring)
        """
        from sage.rings.ring import is_Ring
        if not is_Ring(coeff_ring):
            raise TypeError, 'The coefficient ring must be a ring'
        if not (isinstance(group, str) or group is None):
            raise TypeError, 'The group must be given by a string, or None'
        if not weights in ('even', 'all'):
            raise ValueError, "The argument weights must be 'even' or 'all'" 
        try:
            degree = int(degree)
        except TypeError:
            raise TypeError, 'The degree must be a positive integer'
        if degree < 1:
            raise ValueError, 'The degree must be a positive integer'
        if degree == 1:
            raise ValueError, 'Use ModularForms if you want to work with Siegel modular forms of degree 1'
        if degree > 2:
            raise NotImplementedError, 'Siegel modular forms of degree > 2 are not yet implemented'
        try:
            default_prec = int(default_prec)
        except TypeError:
            raise TypeError, 'The default precision must be a positive integer'
        
        from pushout import SiegelModularFormsAlgebraFunctor
        F = SiegelModularFormsAlgebraFunctor(group=group, weights=weights, degree=degree, default_prec=default_prec) 

        while hasattr(coeff_ring, 'construction'):
            C = coeff_ring.construction()
            if C is None:
                break
            F = F * C[0]
            coeff_ring = C[1]
        return (F, coeff_ring)
Esempio n. 8
0
def LaurentPolynomialRing(base_ring,
                          arg1=None,
                          arg2=None,
                          sparse=False,
                          order='degrevlex',
                          names=None,
                          name=None):
    r"""
    Return the globally unique univariate or multivariate Laurent polynomial
    ring with given properties and variable name or names.

    There are four ways to call the Laurent polynomial ring constructor:

    1. ``LaurentPolynomialRing(base_ring, name,    sparse=False)``
    2. ``LaurentPolynomialRing(base_ring, names,   order='degrevlex')``
    3. ``LaurentPolynomialRing(base_ring, name, n, order='degrevlex')``
    4. ``LaurentPolynomialRing(base_ring, n, name, order='degrevlex')``

    The optional arguments sparse and order *must* be explicitly
    named, and the other arguments must be given positionally.

    INPUT:

    - ``base_ring`` -- a commutative ring
    - ``name`` -- a string
    - ``names`` -- a list or tuple of names, or a comma separated string
    - ``n`` -- a positive integer
    - ``sparse`` -- bool (default: False), whether or not elements are sparse
    - ``order`` -- string or
      :class:`~sage.rings.polynomial.term_order.TermOrder`, e.g.,

        - ``'degrevlex'`` (default) -- degree reverse lexicographic
        - ``'lex'`` -- lexicographic
        - ``'deglex'`` -- degree lexicographic
        - ``TermOrder('deglex',3) + TermOrder('deglex',3)`` -- block ordering

    OUTPUT:

    ``LaurentPolynomialRing(base_ring, name, sparse=False)`` returns a
    univariate Laurent polynomial ring; all other input formats return a
    multivariate Laurent polynomial ring.

    UNIQUENESS and IMMUTABILITY: In Sage there is exactly one
    single-variate Laurent polynomial ring over each base ring in each choice
    of variable and sparseness.  There is also exactly one multivariate
    Laurent polynomial ring over each base ring for each choice of names of
    variables and term order.

    ::

        sage: R.<x,y> = LaurentPolynomialRing(QQ,2); R
        Multivariate Laurent Polynomial Ring in x, y over Rational Field
        sage: f = x^2 - 2*y^-2

    You can't just globally change the names of those variables.
    This is because objects all over Sage could have pointers to
    that polynomial ring.

    ::

        sage: R._assign_names(['z','w'])
        Traceback (most recent call last):
        ...
        ValueError: variable names cannot be changed after object creation.


    EXAMPLES:

    1. ``LaurentPolynomialRing(base_ring, name, sparse=False)``

       ::

           sage: LaurentPolynomialRing(QQ, 'w')
           Univariate Laurent Polynomial Ring in w over Rational Field

       Use the diamond brackets notation to make the variable
       ready for use after you define the ring::

           sage: R.<w> = LaurentPolynomialRing(QQ)
           sage: (1 + w)^3
           1 + 3*w + 3*w^2 + w^3

       You must specify a name::

           sage: LaurentPolynomialRing(QQ)
           Traceback (most recent call last):
           ...
           TypeError: You must specify the names of the variables.

           sage: R.<abc> = LaurentPolynomialRing(QQ, sparse=True); R
           Univariate Laurent Polynomial Ring in abc over Rational Field

           sage: R.<w> = LaurentPolynomialRing(PolynomialRing(GF(7),'k')); R
           Univariate Laurent Polynomial Ring in w over Univariate Polynomial Ring in k over Finite Field of size 7

       Rings with different variables are different::

           sage: LaurentPolynomialRing(QQ, 'x') == LaurentPolynomialRing(QQ, 'y')
           False

    2. ``LaurentPolynomialRing(base_ring, names,   order='degrevlex')``

       ::

           sage: R = LaurentPolynomialRing(QQ, 'a,b,c'); R
           Multivariate Laurent Polynomial Ring in a, b, c over Rational Field

           sage: S = LaurentPolynomialRing(QQ, ['a','b','c']); S
           Multivariate Laurent Polynomial Ring in a, b, c over Rational Field

           sage: T = LaurentPolynomialRing(QQ, ('a','b','c')); T
           Multivariate Laurent Polynomial Ring in a, b, c over Rational Field

       All three rings are identical.

       ::

           sage: (R is S) and  (S is T)
           True

       There is a unique Laurent polynomial ring with each term order::

           sage: R = LaurentPolynomialRing(QQ, 'x,y,z', order='degrevlex'); R
           Multivariate Laurent Polynomial Ring in x, y, z over Rational Field
           sage: S = LaurentPolynomialRing(QQ, 'x,y,z', order='invlex'); S
           Multivariate Laurent Polynomial Ring in x, y, z over Rational Field
           sage: S is LaurentPolynomialRing(QQ, 'x,y,z', order='invlex')
           True
           sage: R == S
           False


    3. ``LaurentPolynomialRing(base_ring, name, n, order='degrevlex')``

       If you specify a single name as a string and a number of
       variables, then variables labeled with numbers are created.

       ::

           sage: LaurentPolynomialRing(QQ, 'x', 10)
           Multivariate Laurent Polynomial Ring in x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 over Rational Field

           sage: LaurentPolynomialRing(GF(7), 'y', 5)
           Multivariate Laurent Polynomial Ring in y0, y1, y2, y3, y4 over Finite Field of size 7

           sage: LaurentPolynomialRing(QQ, 'y', 3, sparse=True)
           Multivariate Laurent Polynomial Ring in y0, y1, y2 over Rational Field

       By calling the
       :meth:`~sage.structure.category_object.CategoryObject.inject_variables`
       method, all those variable names are available for interactive use::

           sage: R = LaurentPolynomialRing(GF(7),15,'w'); R
           Multivariate Laurent Polynomial Ring in w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14 over Finite Field of size 7
           sage: R.inject_variables()
           Defining w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14
           sage: (w0 + 2*w8 + w13)^2
           w0^2 + 4*w0*w8 + 4*w8^2 + 2*w0*w13 + 4*w8*w13 + w13^2
    """
    if is_Element(arg1) and not isinstance(arg1, integer_types + (Integer, )):
        arg1 = repr(arg1)
    if is_Element(arg2) and not isinstance(arg2, integer_types + (Integer, )):
        arg2 = repr(arg2)

    if isinstance(arg1, integer_types + (Integer, )):
        arg1, arg2 = arg2, arg1

    if not names is None:
        arg1 = names
    elif not name is None:
        arg1 = name

    if not is_Ring(base_ring):
        raise TypeError('base_ring must be a ring')

    if arg1 is None:
        raise TypeError("You must specify the names of the variables.")

    R = None
    if isinstance(arg1, (list, tuple)):
        arg1 = [str(x) for x in arg1]
    if isinstance(arg2, (list, tuple)):
        arg2 = [str(x) for x in arg2]
    if isinstance(arg2, integer_types + (Integer, )):
        # 3. LaurentPolynomialRing(base_ring, names, n, order='degrevlex'):
        if not isinstance(arg1, (list, tuple, str)):
            raise TypeError("You *must* specify the names of the variables.")
        n = int(arg2)
        names = arg1
        R = _multi_variate(base_ring, names, n, sparse, order)

    elif isinstance(arg1,
                    str) or (isinstance(arg1, (list, tuple))
                             and len(arg1) == 1) and isinstance(arg1[0], str):
        if isinstance(arg1, (list, tuple)):
            arg1 = arg1[0]
        if not ',' in arg1:
            # 1. LaurentPolynomialRing(base_ring, name, sparse=False):
            if not arg2 is None:
                raise TypeError(
                    "if second arguments is a string with no commas, then there must be no other non-optional arguments"
                )
            name = arg1
            R = _single_variate(base_ring, name, sparse)
        else:
            # 2-4. LaurentPolynomialRing(base_ring, names, order='degrevlex'):
            if not arg2 is None:
                raise TypeError(
                    "invalid input to LaurentPolynomialRing function; please see the docstring for that function"
                )
            names = arg1.split(',')
            n = len(names)
            R = _multi_variate(base_ring, names, n, sparse, order)
    elif isinstance(arg1, (list, tuple)):
        # LaurentPolynomialRing(base_ring, names (list or tuple), order='degrevlex'):
        names = arg1
        n = len(names)
        R = _multi_variate(base_ring, names, n, sparse, order)

    if arg1 is None and arg2 is None:
        raise TypeError("you *must* specify the indeterminates (as not None).")
    if R is None:
        raise TypeError(
            "invalid input (%s, %s, %s) to PolynomialRing function; please see the docstring for that function"
            % (base_ring, arg1, arg2))

    return R
Esempio n. 9
0
    def _element_constructor_(self, x):
        r"""
        Try to turn ``x`` into an element of ``self``.

        INPUT:

        - ``x`` - an element of some group algebra or of a
          ring or of a group

        OUTPUT: ``x`` as a member of ``self``.

            sage: G = KleinFourGroup()
            sage: f = G.gen(0)
            sage: ZG = GroupAlgebra(G)
            sage: ZG(f)  # indirect doctest
            (3,4)
            sage: ZG(1) == ZG(G(1))
            True
            sage: G = AbelianGroup(1)
            sage: ZG = GroupAlgebra(G)
            sage: f = ZG.group().gen()
            sage: ZG(FormalSum([(1,f), (2, f**2)]))
            f + 2*f^2
            sage: G = GL(2,7)
            sage: OG = GroupAlgebra(G, ZZ[sqrt(5)])
            sage: OG(2)
            2*[1 0]
            [0 1]
            sage: OG(G(2)) # conversion is not the obvious one
            [2 0]
            [0 2]
            sage: OG(FormalSum([ (1, G(2)), (2, RR(0.77)) ]) )
            Traceback (most recent call last):
            ...
            TypeError: Attempt to coerce non-integral RealNumber to Integer
            sage: OG(OG.base_ring().basis()[1])
            sqrt5*[1 0]
            [0 1]
        """
        from sage.rings.ring import is_Ring
        from sage.groups.group import is_Group
        from sage.structure.formal_sum import FormalSum
        k = self.base_ring()
        G = self.group()
        S = x.parent()
        if isinstance(S, GroupAlgebra):
            if self.has_coerce_map_from(S):
                # coerce monomials, coerce coefficients, reassemble
                d = x.monomial_coefficients()
                new_d = {}
                for g in d:
                    g1 = G(g)
                    if g1 in new_d:
                        new_d[g1] += k(d[g]) + new_d[g1]
                    else:
                        new_d[g1] = k(d[g])
                return self._from_dict(new_d)
        elif is_Ring(S):
            # coerce to multiple of identity element
            return k(x) * self(1)
        elif is_Group(S):
            # Check whether group coerces to base_ring first.
            if k.has_coerce_map_from(S):
                return k(x) * self(1)
            if G.has_coerce_map_from(S):
                return self.monomial(self.group()(x))
        elif isinstance(x, FormalSum) and k.has_coerce_map_from(S.base_ring()):
            y = [(G(g), k(coeff)) for coeff, g in x]
            return self.sum_of_terms(y)
        raise TypeError("Don't know how to create an element of %s from %s" % \
                             (self, x))
Esempio n. 10
0
def PolynomialRing(base_ring, *args, **kwds):
    r"""
    Return the globally unique univariate or multivariate polynomial
    ring with given properties and variable name or names.

    There are many ways to specify the variables for the polynomial ring:

    1. ``PolynomialRing(base_ring, name, ...)``
    2. ``PolynomialRing(base_ring, names, ...)``
    3. ``PolynomialRing(base_ring, n, names, ...)``
    4. ``PolynomialRing(base_ring, n, ..., var_array=var_array, ...)``

    The ``...`` at the end of these commands stands for additional
    keywords, like ``sparse`` or ``order``.

    INPUT:

    - ``base_ring`` -- a ring

    - ``n`` -- an integer

    - ``name`` -- a string

    - ``names`` -- a list or tuple of names (strings), or a comma separated string

    - ``var_array`` -- a list or tuple of names, or a comma separated string

    - ``sparse`` -- bool: whether or not elements are sparse. The
      default is a dense representation (``sparse=False``) for
      univariate rings and a sparse representation (``sparse=True``)
      for multivariate rings.

    - ``order`` -- string or
      :class:`~sage.rings.polynomial.term_order.TermOrder` object, e.g.,

      - ``'degrevlex'`` (default) -- degree reverse lexicographic
      - ``'lex'``  -- lexicographic
      - ``'deglex'`` -- degree lexicographic
      - ``TermOrder('deglex',3) + TermOrder('deglex',3)`` -- block ordering

    - ``implementation`` -- string or None; selects an implementation in cases
      where Sage includes multiple choices (currently `\ZZ[x]` can be
      implemented with ``'NTL'`` or ``'FLINT'``; default is ``'FLINT'``).
      For many base rings, the ``"singular"`` implementation is available.
      One can always specify ``implementation="generic"`` for a generic
      Sage implementation which does not use any specialized library.

    .. NOTE::

        If the given implementation does not exist for rings with the given
        number of generators and the given sparsity, then an error results.

    OUTPUT:

    ``PolynomialRing(base_ring, name, sparse=False)`` returns a univariate
    polynomial ring; also, PolynomialRing(base_ring, names, sparse=False)
    yields a univariate polynomial ring, if names is a list or tuple
    providing exactly one name. All other input formats return a
    multivariate polynomial ring.

    UNIQUENESS and IMMUTABILITY: In Sage there is exactly one
    single-variate polynomial ring over each base ring in each choice
    of variable, sparseness, and implementation.  There is also exactly
    one multivariate polynomial ring over each base ring for each
    choice of names of variables and term order.  The names of the
    generators can only be temporarily changed after the ring has been
    created.  Do this using the localvars context:

    EXAMPLES:

    **1. PolynomialRing(base_ring, name, ...)**

    ::

        sage: PolynomialRing(QQ, 'w')
        Univariate Polynomial Ring in w over Rational Field
        sage: PolynomialRing(QQ, name='w')
        Univariate Polynomial Ring in w over Rational Field

    Use the diamond brackets notation to make the variable
    ready for use after you define the ring::

        sage: R.<w> = PolynomialRing(QQ)
        sage: (1 + w)^3
        w^3 + 3*w^2 + 3*w + 1

    You must specify a name::

        sage: PolynomialRing(QQ)
        Traceback (most recent call last):
        ...
        TypeError: you must specify the names of the variables

        sage: R.<abc> = PolynomialRing(QQ, sparse=True); R
        Sparse Univariate Polynomial Ring in abc over Rational Field

        sage: R.<w> = PolynomialRing(PolynomialRing(GF(7),'k')); R
        Univariate Polynomial Ring in w over Univariate Polynomial Ring in k over Finite Field of size 7

    The square bracket notation::

        sage: R.<y> = QQ['y']; R
        Univariate Polynomial Ring in y over Rational Field
        sage: y^2 + y
        y^2 + y

    In fact, since the diamond brackets on the left determine the
    variable name, you can omit the variable from the square brackets::

        sage: R.<zz> = QQ[]; R
        Univariate Polynomial Ring in zz over Rational Field
        sage: (zz + 1)^2
        zz^2 + 2*zz + 1

    This is exactly the same ring as what PolynomialRing returns::

        sage: R is PolynomialRing(QQ,'zz')
        True

    However, rings with different variables are different::

        sage: QQ['x'] == QQ['y']
        False

    Sage has two implementations of univariate polynomials over the
    integers, one based on NTL and one based on FLINT.  The default
    is FLINT. Note that FLINT uses a "more dense" representation for
    its polynomials than NTL, so in particular, creating a polynomial
    like 2^1000000 * x^1000000 in FLINT may be unwise.
    ::

        sage: ZxNTL = PolynomialRing(ZZ, 'x', implementation='NTL'); ZxNTL
        Univariate Polynomial Ring in x over Integer Ring (using NTL)
        sage: ZxFLINT = PolynomialRing(ZZ, 'x', implementation='FLINT'); ZxFLINT
        Univariate Polynomial Ring in x over Integer Ring
        sage: ZxFLINT is ZZ['x']
        True
        sage: ZxFLINT is PolynomialRing(ZZ, 'x')
        True
        sage: xNTL = ZxNTL.gen()
        sage: xFLINT = ZxFLINT.gen()
        sage: xNTL.parent()
        Univariate Polynomial Ring in x over Integer Ring (using NTL)
        sage: xFLINT.parent()
        Univariate Polynomial Ring in x over Integer Ring

    There is a coercion from the non-default to the default
    implementation, so the values can be mixed in a single
    expression::

        sage: (xNTL + xFLINT^2)
        x^2 + x

    The result of such an expression will use the default, i.e.,
    the FLINT implementation::

        sage: (xNTL + xFLINT^2).parent()
        Univariate Polynomial Ring in x over Integer Ring

    The generic implementation uses neither NTL nor FLINT::

        sage: Zx = PolynomialRing(ZZ, 'x', implementation='generic'); Zx
        Univariate Polynomial Ring in x over Integer Ring
        sage: Zx.element_class
        <... 'sage.rings.polynomial.polynomial_element.Polynomial_generic_dense'>

    **2. PolynomialRing(base_ring, names, ...)**

    ::

        sage: R = PolynomialRing(QQ, 'a,b,c'); R
        Multivariate Polynomial Ring in a, b, c over Rational Field

        sage: S = PolynomialRing(QQ, ['a','b','c']); S
        Multivariate Polynomial Ring in a, b, c over Rational Field

        sage: T = PolynomialRing(QQ, ('a','b','c')); T
        Multivariate Polynomial Ring in a, b, c over Rational Field

    All three rings are identical::

        sage: R is S
        True
        sage: S is T
        True

    There is a unique polynomial ring with each term order::

        sage: R = PolynomialRing(QQ, 'x,y,z', order='degrevlex'); R
        Multivariate Polynomial Ring in x, y, z over Rational Field
        sage: S = PolynomialRing(QQ, 'x,y,z', order='invlex'); S
        Multivariate Polynomial Ring in x, y, z over Rational Field
        sage: S is PolynomialRing(QQ, 'x,y,z', order='invlex')
        True
        sage: R == S
        False

    Note that a univariate polynomial ring is returned, if the list
    of names is of length one. If it is of length zero, a multivariate
    polynomial ring with no variables is returned.

    ::

        sage: PolynomialRing(QQ,["x"])
        Univariate Polynomial Ring in x over Rational Field
        sage: PolynomialRing(QQ,[])
        Multivariate Polynomial Ring in no variables over Rational Field

    The Singular implementation always returns a multivariate ring,
    even for 1 variable::

        sage: PolynomialRing(QQ, "x", implementation="singular")
        Multivariate Polynomial Ring in x over Rational Field
        sage: P.<x> = PolynomialRing(QQ, implementation="singular"); P
        Multivariate Polynomial Ring in x over Rational Field

    **3. PolynomialRing(base_ring, n, names, ...)** (where the arguments
    ``n`` and ``names`` may be reversed)

    If you specify a single name as a string and a number of
    variables, then variables labeled with numbers are created.

    ::

        sage: PolynomialRing(QQ, 'x', 10)
        Multivariate Polynomial Ring in x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 over Rational Field

        sage: PolynomialRing(QQ, 2, 'alpha0')
        Multivariate Polynomial Ring in alpha00, alpha01 over Rational Field

        sage: PolynomialRing(GF(7), 'y', 5)
        Multivariate Polynomial Ring in y0, y1, y2, y3, y4 over Finite Field of size 7

        sage: PolynomialRing(QQ, 'y', 3, sparse=True)
        Multivariate Polynomial Ring in y0, y1, y2 over Rational Field

    Note that a multivariate polynomial ring is returned when an
    explicit number is given.

    ::

        sage: PolynomialRing(QQ,"x",1)
        Multivariate Polynomial Ring in x over Rational Field
        sage: PolynomialRing(QQ,"x",0)
        Multivariate Polynomial Ring in no variables over Rational Field

    It is easy in Python to create fairly arbitrary variable names.  For
    example, here is a ring with generators labeled by the primes less
    than 100::

        sage: R = PolynomialRing(ZZ, ['x%s'%p for p in primes(100)]); R
        Multivariate Polynomial Ring in x2, x3, x5, x7, x11, x13, x17, x19, x23, x29, x31, x37, x41, x43, x47, x53, x59, x61, x67, x71, x73, x79, x83, x89, x97 over Integer Ring

    By calling the
    :meth:`~sage.structure.category_object.CategoryObject.inject_variables`
    method, all those variable names are available for interactive use::

        sage: R.inject_variables()
        Defining x2, x3, x5, x7, x11, x13, x17, x19, x23, x29, x31, x37, x41, x43, x47, x53, x59, x61, x67, x71, x73, x79, x83, x89, x97
        sage: (x2 + x41 + x71)^2
        x2^2 + 2*x2*x41 + x41^2 + 2*x2*x71 + 2*x41*x71 + x71^2

    **4. PolynomialRing(base_ring, n, ..., var_array=var_array, ...)**

    This creates an array of variables where each variables begins with an
    entry in ``var_array`` and is indexed from 0 to `n-1`. ::

        sage: PolynomialRing(ZZ, 3, var_array=['x','y'])
        Multivariate Polynomial Ring in x0, y0, x1, y1, x2, y2 over Integer Ring
        sage: PolynomialRing(ZZ, 3, var_array='a,b')
        Multivariate Polynomial Ring in a0, b0, a1, b1, a2, b2 over Integer Ring

    It is possible to create higher-dimensional arrays::

        sage: PolynomialRing(ZZ, 2, 3, var_array=('p', 'q'))
        Multivariate Polynomial Ring in p00, q00, p01, q01, p02, q02, p10, q10, p11, q11, p12, q12 over Integer Ring
        sage: PolynomialRing(ZZ, 2, 3, 4, var_array='m')
        Multivariate Polynomial Ring in m000, m001, m002, m003, m010, m011, m012, m013, m020, m021, m022, m023, m100, m101, m102, m103, m110, m111, m112, m113, m120, m121, m122, m123 over Integer Ring

    The array is always at least 2-dimensional. So, if
    ``var_array`` is a single string and only a single number `n`
    is given, this creates an `n \times n` array of variables::

        sage: PolynomialRing(ZZ, 2, var_array='m')
        Multivariate Polynomial Ring in m00, m01, m10, m11 over Integer Ring

    **Square brackets notation**

    You can alternatively create a polynomial ring over a ring `R` with
    square brackets::

        sage: RR["x"]
        Univariate Polynomial Ring in x over Real Field with 53 bits of precision
        sage: RR["x,y"]
        Multivariate Polynomial Ring in x, y over Real Field with 53 bits of precision
        sage: P.<x,y> = RR[]; P
        Multivariate Polynomial Ring in x, y over Real Field with 53 bits of precision

    This notation does not allow to set any of the optional arguments.

    **Changing variable names**

    Consider ::

        sage: R.<x,y> = PolynomialRing(QQ,2); R
        Multivariate Polynomial Ring in x, y over Rational Field
        sage: f = x^2 - 2*y^2

    You can't just globally change the names of those variables.
    This is because objects all over Sage could have pointers to
    that polynomial ring. ::

        sage: R._assign_names(['z','w'])
        Traceback (most recent call last):
        ...
        ValueError: variable names cannot be changed after object creation.

    However, you can very easily change the names within a ``with`` block::

        sage: with localvars(R, ['z','w']):
        ....:     print(f)
        z^2 - 2*w^2

    After the ``with`` block the names revert to what they were before::

        sage: print(f)
        x^2 - 2*y^2

    TESTS:

    We test here some changes introduced in :trac:`9944`.

    If there is no dense implementation for the given number of
    variables, then requesting a dense ring is an error::

        sage: S.<x,y> = PolynomialRing(QQ, sparse=False)
        Traceback (most recent call last):
        ...
        NotImplementedError: a dense representation of multivariate polynomials is not supported

    Check uniqueness if the same implementation is used for different
    values of the ``"implementation"`` keyword::

        sage: R = PolynomialRing(QQbar, 'j', implementation="generic")
        sage: S = PolynomialRing(QQbar, 'j', implementation=None)
        sage: R is S
        True

        sage: R = PolynomialRing(ZZ['t'], 'j', implementation="generic")
        sage: S = PolynomialRing(ZZ['t'], 'j', implementation=None)
        sage: R is S
        True

        sage: R = PolynomialRing(QQbar, 'j,k', implementation="generic")
        sage: S = PolynomialRing(QQbar, 'j,k', implementation=None)
        sage: R is S
        True

        sage: R = PolynomialRing(ZZ, 'j,k', implementation="singular")
        sage: S = PolynomialRing(ZZ, 'j,k', implementation=None)
        sage: R is S
        True

        sage: R = PolynomialRing(ZZ, 'p', sparse=True, implementation="generic")
        sage: S = PolynomialRing(ZZ, 'p', sparse=True)
        sage: R is S
        True

    The generic implementation is different in some cases::

        sage: R = PolynomialRing(GF(2), 'j', implementation="generic"); type(R)
        <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_field_with_category'>
        sage: S = PolynomialRing(GF(2), 'j'); type(S)
        <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_dense_mod_p_with_category'>

        sage: R = PolynomialRing(ZZ, 'x,y', implementation="generic"); type(R)
        <class 'sage.rings.polynomial.multi_polynomial_ring.MPolynomialRing_polydict_domain_with_category'>
        sage: S = PolynomialRing(ZZ, 'x,y'); type(S)
        <type 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomialRing_libsingular'>

    Sparse univariate polynomials only support a generic
    implementation::

        sage: R = PolynomialRing(ZZ, 'j', sparse=True); type(R)
        <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_integral_domain_with_category'>
        sage: R = PolynomialRing(GF(49), 'j', sparse=True); type(R)
        <class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_field_with_category'>

    If the requested implementation is not known or not supported for
    the given arguments, then an error results::

        sage: R.<x0> = PolynomialRing(ZZ, implementation='Foo')
        Traceback (most recent call last):
        ...
        ValueError: unknown implementation 'Foo' for dense polynomial rings over Integer Ring
        sage: R.<x0> = PolynomialRing(GF(2), implementation='GF2X', sparse=True)
        Traceback (most recent call last):
        ...
        ValueError: unknown implementation 'GF2X' for sparse polynomial rings over Finite Field of size 2
        sage: R.<x,y> = PolynomialRing(ZZ, implementation='FLINT')
        Traceback (most recent call last):
        ...
        ValueError: unknown implementation 'FLINT' for multivariate polynomial rings
        sage: R.<x> = PolynomialRing(QQbar, implementation="whatever")
        Traceback (most recent call last):
        ...
        ValueError: unknown implementation 'whatever' for dense polynomial rings over Algebraic Field
        sage: R.<x> = PolynomialRing(ZZ['t'], implementation="whatever")
        Traceback (most recent call last):
        ...
        ValueError: unknown implementation 'whatever' for dense polynomial rings over Univariate Polynomial Ring in t over Integer Ring
        sage: PolynomialRing(RR, "x,y", implementation="whatever")
        Traceback (most recent call last):
        ...
        ValueError: unknown implementation 'whatever' for multivariate polynomial rings
        sage: PolynomialRing(RR, name="x", implementation="singular")
        Traceback (most recent call last):
        ...
        NotImplementedError: polynomials over Real Field with 53 bits of precision are not supported in Singular

    The following corner case used to result in a warning message from
    ``libSingular``, and the generators of the resulting polynomial
    ring were not zero::

        sage: R = Integers(1)['x','y']
        sage: R.0 == 0
        True

    We verify that :trac:`13187` is fixed::

        sage: var('t')
        t
        sage: PolynomialRing(ZZ, name=t) == PolynomialRing(ZZ, name='t')
        True

    We verify that polynomials with interval coefficients from
    :trac:`7712` and :trac:`13760` are fixed::

        sage: P.<y,z> = PolynomialRing(RealIntervalField(2))
        sage: Q.<x> = PolynomialRing(P)
        sage: C = (y-x)^3
        sage: C(y/2)
        1.?*y^3
        sage: R.<x,y> = PolynomialRing(RIF,2)
        sage: RIF(-2,1)*x
        0.?e1*x

    For historical reasons, we allow redundant variable names with the
    angle bracket notation. The names must be consistent though! ::

        sage: P.<x,y> = PolynomialRing(ZZ, "x,y"); P
        Multivariate Polynomial Ring in x, y over Integer Ring
        sage: P.<x,y> = ZZ["x,y"]; P
        Multivariate Polynomial Ring in x, y over Integer Ring
        sage: P.<x,y> = PolynomialRing(ZZ, 2, "x"); P
        Traceback (most recent call last):
        ...
        TypeError: variable names specified twice inconsistently: ('x0', 'x1') and ('x', 'y')

    We test a lot of invalid input::

        sage: PolynomialRing(4)
        Traceback (most recent call last):
        ...
        TypeError: base_ring 4 must be a ring
        sage: PolynomialRing(QQ, -1)
        Traceback (most recent call last):
        ...
        ValueError: number of variables must be non-negative
        sage: PolynomialRing(QQ, 1)
        Traceback (most recent call last):
        ...
        TypeError: you must specify the names of the variables
        sage: PolynomialRing(QQ, "x", None)
        Traceback (most recent call last):
        ...
        TypeError: invalid arguments ('x', None) for PolynomialRing
        sage: PolynomialRing(QQ, "x", "y")
        Traceback (most recent call last):
        ...
        TypeError: variable names specified twice: 'x' and 'y'
        sage: PolynomialRing(QQ, 1, "x", 2)
        Traceback (most recent call last):
        ...
        TypeError: number of variables specified twice: 1 and 2
        sage: PolynomialRing(QQ, "x", names="x")
        Traceback (most recent call last):
        ...
        TypeError: variable names specified twice inconsistently: ('x',) and 'x'
        sage: PolynomialRing(QQ, name="x", names="x")
        Traceback (most recent call last):
        ...
        TypeError: keyword argument 'name' cannot be combined with 'names'
        sage: PolynomialRing(QQ, var_array='x')
        Traceback (most recent call last):
        ...
        TypeError: you must specify the number of the variables
        sage: PolynomialRing(QQ, 2, 'x', var_array='x')
        Traceback (most recent call last):
        ...
        TypeError: unable to convert 'x' to an integer
    """
    if not ring.is_Ring(base_ring):
        raise TypeError("base_ring {!r} must be a ring".format(base_ring))

    n = -1  # Unknown number of variables
    names = None  # Unknown variable names

    # Use a single-variate ring by default unless the "singular"
    # implementation is asked.
    multivariate = kwds.get("implementation") == "singular"

    # Check specifically for None because it is an easy mistake to
    # make and Integer(None) returns 0, so we wouldn't catch this
    # otherwise.
    if any(arg is None for arg in args):
        raise TypeError(
            "invalid arguments {!r} for PolynomialRing".format(args))

    if "var_array" in kwds:
        for forbidden in "name", "names":
            if forbidden in kwds:
                raise TypeError(
                    "keyword argument '%s' cannot be combined with 'var_array'"
                    % forbidden)

        names = kwds.pop("var_array")
        if isinstance(names, (tuple, list)):
            # Input is a 1-dimensional array
            dim = 1
        else:
            # Input is a 0-dimensional (if a single string was given)
            # or a 1-dimensional array
            names = normalize_names(-1, names)
            dim = len(names) > 1
        multivariate = True

        if not args:
            raise TypeError("you must specify the number of the variables")
        # The total dimension must be at least 2
        if len(args) == 1 and not dim:
            args = [args[0], args[0]]

        # All arguments in *args should be a number of variables
        suffixes = [""]
        for arg in args:
            k = Integer(arg)
            if k < 0:
                raise ValueError("number of variables must be non-negative")
            suffixes = [s + str(i) for s in suffixes for i in range(k)]
        names = [v + s for s in suffixes for v in names]
    else:  # No "var_array" keyword
        if "name" in kwds:
            if "names" in kwds:
                raise TypeError(
                    "keyword argument 'name' cannot be combined with 'names'")
            names = [kwds.pop("name")]

        # Interpret remaining arguments in *args as either a number of
        # variables or as variable names
        for arg in args:
            try:
                k = Integer(arg)
            except TypeError:
                # Interpret arg as names
                if names is not None:
                    raise TypeError(
                        "variable names specified twice: %r and %r" %
                        (names, arg))
                names = arg
            else:
                # Interpret arg as number of variables
                if n >= 0:
                    raise TypeError(
                        "number of variables specified twice: %r and %r" %
                        (n, arg))
                if k < 0:
                    raise ValueError(
                        "number of variables must be non-negative")
                n = k
                # If number of variables was explicitly given, always
                # return a multivariate ring
                multivariate = True

    if names is None:
        try:
            names = kwds.pop("names")
        except KeyError:
            raise TypeError("you must specify the names of the variables")

    names = normalize_names(n, names)

    # At this point, we have only handled the "names" keyword if it was
    # needed. Since we know the variable names, it would logically be
    # an error to specify an additional "names" keyword. However,
    # people often abuse the preparser with
    #   R.<x> = PolynomialRing(QQ, 'x')
    # and we allow this for historical reasons. However, the names
    # must be consistent!
    if "names" in kwds:
        kwnames = kwds.pop("names")
        if kwnames != names:
            raise TypeError(
                "variable names specified twice inconsistently: %r and %r" %
                (names, kwnames))

    if multivariate or len(names) != 1:
        return _multi_variate(base_ring, names, **kwds)
    else:
        return _single_variate(base_ring, names, **kwds)
Esempio n. 11
0
def EllipticCurve(x=None, y=None, j=None, minimal_twist=True):
    r"""
    Construct an elliptic curve.

    In Sage, an elliptic curve is always specified by its a-invariants

    .. math::

       y^2 + a_1 xy + a_3 y = x^3 + a_2 x^2 + a_4 x + a_6.

    INPUT:

    There are several ways to construct an elliptic curve:

    - ``EllipticCurve([a1,a2,a3,a4,a6])``: Elliptic curve with given
      a-invariants. The invariants are coerced into the parent of the
      first element. If all are integers, they are coerced into the
      rational numbers.

    - ``EllipticCurve([a4,a6])``: Same as above, but `a_1=a_2=a_3=0`.

    - ``EllipticCurve(label)``: Returns the elliptic curve over Q from
      the Cremona database with the given label. The label is a
      string, such as ``"11a"`` or ``"37b2"``. The letters in the
      label *must* be lower case (Cremona's new labeling).

    - ``EllipticCurve(R, [a1,a2,a3,a4,a6])``: Create the elliptic
      curve over ``R`` with given a-invariants. Here ``R`` can be an
      arbitrary ring. Note that addition need not be defined.

    - ``EllipticCurve(j=j0)`` or ``EllipticCurve_from_j(j0)``: Return
      an elliptic curve with j-invariant ``j0``.

    - ``EllipticCurve(polynomial)``: Read off the a-invariants from
      the polynomial coefficients, see
      :func:`EllipticCurve_from_Weierstrass_polynomial`.

    In each case above where the input is a list of length 2 or 5, one
    can instead give a 2 or 5-tuple instead.

    EXAMPLES:

    We illustrate creating elliptic curves::

        sage: EllipticCurve([0,0,1,-1,0])
        Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field

    We create a curve from a Cremona label::

        sage: EllipticCurve('37b2')
        Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field
        sage: EllipticCurve('5077a')
        Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field
        sage: EllipticCurve('389a')
        Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field

    Old Cremona labels are allowed::

        sage: EllipticCurve('2400FF')
        Elliptic Curve defined by y^2 = x^3 + x^2 + 2*x + 8 over Rational Field

    Unicode labels are allowed::

        sage: EllipticCurve(u'389a')
        Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field

    We create curves over a finite field as follows::

        sage: EllipticCurve([GF(5)(0),0,1,-1,0])
        Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5
        sage: EllipticCurve(GF(5), [0, 0,1,-1,0])
        Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5

    Elliptic curves over `\ZZ/N\ZZ` with `N` prime are of type
    "elliptic curve over a finite field"::

        sage: F = Zmod(101)
        sage: EllipticCurve(F, [2, 3])
        Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 101
        sage: E = EllipticCurve([F(2), F(3)])
        sage: type(E)
        <class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field_with_category'>
        sage: E.category()
        Category of schemes over Ring of integers modulo 101

    In contrast, elliptic curves over `\ZZ/N\ZZ` with `N` composite
    are of type "generic elliptic curve"::

        sage: F = Zmod(95)
        sage: EllipticCurve(F, [2, 3])
        Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 95
        sage: E = EllipticCurve([F(2), F(3)])
        sage: type(E)
        <class 'sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic_with_category'>
        sage: E.category()
        Category of schemes over Ring of integers modulo 95

    The following is a curve over the complex numbers::

        sage: E = EllipticCurve(CC, [0,0,1,-1,0])
        sage: E
        Elliptic Curve defined by y^2 + 1.00000000000000*y = x^3 + (-1.00000000000000)*x over Complex Field with 53 bits of precision
        sage: E.j_invariant()
        2988.97297297297

    We can also create elliptic curves by giving the Weierstrass equation::

        sage: x, y = var('x,y')
        sage: EllipticCurve(y^2 + y ==  x^3 + x - 9)
        Elliptic Curve defined by y^2 + y = x^3 + x - 9 over Rational Field

        sage: R.<x,y> = GF(5)[]
        sage: EllipticCurve(x^3 + x^2 + 2 - y^2 - y*x)
        Elliptic Curve defined by y^2 + x*y  = x^3 + x^2 + 2 over Finite Field of size 5

    We can explicitly specify the `j`-invariant::

        sage: E = EllipticCurve(j=1728); E; E.j_invariant(); E.label()
        Elliptic Curve defined by y^2 = x^3 - x over Rational Field
        1728
        '32a2'

        sage: E = EllipticCurve(j=GF(5)(2)); E; E.j_invariant()
        Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5
        2

    See :trac:`6657` ::

        sage: EllipticCurve(GF(144169),j=1728)
        Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 144169

    By default, when a rational value of `j` is given, the constructed
    curve is a minimal twist (minimal conductor for curves with that
    `j`-invariant).  This can be changed by setting the optional
    parameter ``minimal_twist``, which is True by default, to False::


        sage: EllipticCurve(j=100)
        Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field
        sage: E =EllipticCurve(j=100); E
        Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field
        sage: E.conductor()
        33129800
        sage: E.j_invariant()
        100
        sage: E =EllipticCurve(j=100, minimal_twist=False); E
        Elliptic Curve defined by y^2 = x^3 + 488400*x - 530076800 over Rational Field
        sage: E.conductor()
        298168200
        sage: E.j_invariant()
        100

    Without this option, constructing the curve could take a long time
    since both `j` and `j-1728` have to be factored to compute the
    minimal twist (see :trac:`13100`)::

       sage: E = EllipticCurve_from_j(2^256+1,minimal_twist=False)
       sage: E.j_invariant() == 2^256+1
       True

    TESTS::

        sage: R = ZZ['u', 'v']
        sage: EllipticCurve(R, [1,1])
        Elliptic Curve defined by y^2 = x^3 + x + 1 over Multivariate Polynomial Ring in u, v
        over Integer Ring

    We create a curve and a point over QQbar (see #6879)::

        sage: E = EllipticCurve(QQbar,[0,1])
        sage: E(0)
        (0 : 1 : 0)
        sage: E.base_field()
        Algebraic Field

        sage: E = EllipticCurve(RR,[1,2]); E; E.base_field()
        Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision
        Real Field with 53 bits of precision
        sage: EllipticCurve(CC,[3,4]); E; E.base_field()
        Elliptic Curve defined by y^2 = x^3 + 3.00000000000000*x + 4.00000000000000 over Complex Field with 53 bits of precision
        Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision
        Real Field with 53 bits of precision
        sage: E = EllipticCurve(QQbar,[5,6]); E; E.base_field()
        Elliptic Curve defined by y^2 = x^3 + 5*x + 6 over Algebraic Field
        Algebraic Field

    See :trac:`6657` ::

        sage: EllipticCurve(3,j=1728)
        Traceback (most recent call last):
        ...
        ValueError: First parameter (if present) must be a ring when j is specified

        sage: EllipticCurve(GF(5),j=3/5)
        Traceback (most recent call last):
        ...
        ValueError: First parameter must be a ring containing 3/5

    If the universe of the coefficients is a general field, the object
    constructed has type EllipticCurve_field.  Otherwise it is
    EllipticCurve_generic.  See :trac:`9816` ::

        sage: E = EllipticCurve([QQbar(1),3]); E
        Elliptic Curve defined by y^2 = x^3 + x + 3 over Algebraic Field
        sage: type(E)
        <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'>

        sage: E = EllipticCurve([RR(1),3]); E
        Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 3.00000000000000 over Real Field with 53 bits of precision
        sage: type(E)
        <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'>

        sage: E = EllipticCurve([i,i]); E
        Elliptic Curve defined by y^2 = x^3 + I*x + I over Symbolic Ring
        sage: type(E)
        <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'>
        sage: E.category()
        Category of schemes over Symbolic Ring
        sage: SR in Fields()
        True

        sage: F = FractionField(PolynomialRing(QQ,'t'))
        sage: t = F.gen()
        sage: E = EllipticCurve([t,0]); E
        Elliptic Curve defined by y^2 = x^3 + t*x over Fraction Field of Univariate Polynomial Ring in t over Rational Field
        sage: type(E)
        <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'>
        sage: E.category()
        Category of schemes over Fraction Field of Univariate Polynomial Ring in t over Rational Field

    See :trac:`12517`::

        sage: E = EllipticCurve([1..5])
        sage: EllipticCurve(E.a_invariants())
        Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field

    See :trac:`11773`::

        sage: E = EllipticCurve()
        Traceback (most recent call last):
        ...
        TypeError: invalid input to EllipticCurve constructor

    """
    import ell_generic, ell_field, ell_finite_field, ell_number_field, ell_rational_field, ell_padic_field  # here to avoid circular includes

    if j is not None:
        if not x is None:
            if is_Ring(x):
                try:
                    j = x(j)
                except (ZeroDivisionError, ValueError, TypeError):
                    raise ValueError, "First parameter must be a ring containing %s"%j
            else:
                raise ValueError, "First parameter (if present) must be a ring when j is specified"
        return EllipticCurve_from_j(j, minimal_twist)

    if x is None:
        raise TypeError, "invalid input to EllipticCurve constructor"

    if is_SymbolicEquation(x):
        x = x.lhs() - x.rhs()

    if parent(x) is SR:
        x = x._polynomial_(rings.QQ['x', 'y'])

    if is_MPolynomial(x):
        if y is None:
            return EllipticCurve_from_Weierstrass_polynomial(x)
        else:
            return EllipticCurve_from_cubic(x, y, morphism=False)

    if is_Ring(x):
        if is_RationalField(x):
            return ell_rational_field.EllipticCurve_rational_field(x, y)
        elif is_FiniteField(x) or (is_IntegerModRing(x) and x.characteristic().is_prime()):
            return ell_finite_field.EllipticCurve_finite_field(x, y)
        elif rings.is_pAdicField(x):
            return ell_padic_field.EllipticCurve_padic_field(x, y)
        elif is_NumberField(x):
            return ell_number_field.EllipticCurve_number_field(x, y)
        elif x in _Fields:
            return ell_field.EllipticCurve_field(x, y)
        return ell_generic.EllipticCurve_generic(x, y)

    if isinstance(x, unicode):
        x = str(x)

    if isinstance(x, basestring):
        return ell_rational_field.EllipticCurve_rational_field(x)

    if is_RingElement(x) and y is None:
        raise TypeError, "invalid input to EllipticCurve constructor"

    if not isinstance(x, (list, tuple)):
        raise TypeError, "invalid input to EllipticCurve constructor"

    x = Sequence(x)
    if not (len(x) in [2,5]):
        raise ValueError, "sequence of coefficients must have length 2 or 5"
    R = x.universe()

    if isinstance(x[0], (rings.Rational, rings.Integer, int, long)):
        return ell_rational_field.EllipticCurve_rational_field(x, y)

    elif is_NumberField(R):
        return ell_number_field.EllipticCurve_number_field(x, y)

    elif rings.is_pAdicField(R):
        return ell_padic_field.EllipticCurve_padic_field(x, y)

    elif is_FiniteField(R) or (is_IntegerModRing(R) and R.characteristic().is_prime()):
        return ell_finite_field.EllipticCurve_finite_field(x, y)

    elif R in _Fields:
        return ell_field.EllipticCurve_field(x, y)

    return ell_generic.EllipticCurve_generic(x, y)
Esempio n. 12
0
    def _element_constructor_(self, x):
        r"""
        Try to turn ``x`` into an element of ``self``.

        INPUT:

        - ``x`` - an element of some group algebra or of a
          ring or of a group

        OUTPUT: ``x`` as a member of ``self``.

            sage: G = KleinFourGroup()
            sage: f = G.gen(0)
            sage: ZG = GroupAlgebra(G)
            sage: ZG(f)  # indirect doctest
            (3,4)
            sage: ZG(1) == ZG(G(1))
            True
            sage: G = AbelianGroup(1)
            sage: ZG = GroupAlgebra(G)
            sage: f = ZG.group().gen()
            sage: ZG(FormalSum([(1,f), (2, f**2)]))
            f + 2*f^2
            sage: G = GL(2,7)
            sage: OG = GroupAlgebra(G, ZZ[sqrt(5)])
            sage: OG(2)
            2*[1 0]
            [0 1]
            sage: OG(G(2)) # conversion is not the obvious one
            [2 0]
            [0 2]
            sage: OG(FormalSum([ (1, G(2)), (2, RR(0.77)) ]) )
            Traceback (most recent call last):
            ...
            TypeError: Attempt to coerce non-integral RealNumber to Integer
            sage: OG(OG.base_ring().basis()[1])
            sqrt5*[1 0]
            [0 1]
        """
        from sage.rings.ring import is_Ring
        from sage.groups.group import is_Group
        from sage.structure.formal_sum import FormalSum
        k = self.base_ring()
        G = self.group()
        S = x.parent()
        if isinstance(S, GroupAlgebra):
            if self.has_coerce_map_from(S):
                # coerce monomials, coerce coefficients, reassemble
                d = x.monomial_coefficients()
                new_d = {}
                for g in d:
                    g1 = G(g)
                    if g1 in new_d:
                        new_d[g1] += k(d[g]) + new_d[g1]
                    else:
                        new_d[g1] = k(d[g])
                return self._from_dict(new_d)
        elif is_Ring(S):
            # coerce to multiple of identity element
            return k(x) * self(1)
        elif is_Group(S):
            # Check whether group coerces to base_ring first.
            if k.has_coerce_map_from(S):
                return k(x) * self(1)
            if G.has_coerce_map_from(S):
                return self.monomial(self.group()(x))
        elif isinstance(x, FormalSum) and k.has_coerce_map_from(S.base_ring()):
            y = [(G(g), k(coeff)) for coeff,g in x]
            return self.sum_of_terms(y)
        raise TypeError("Don't know how to create an element of %s from %s" % \
                             (self, x))
Esempio n. 13
0
def random_quadraticform(R, n, rand_arg_list=[]):
    """
    Create a random quadratic form in `n` variables defined over the ring `R`.

    The last (and optional) argument ``rand_arg_list`` is a list of at most 3
    elements which is passed (as at most 3 separate variables) into the method
    ``R.random_element()``.

    INPUT:

    - `R` -- a ring.
    - `n` -- an integer `\ge 0`
    - ``rand_arg_list`` -- a list of at most 3 arguments which can be taken by
      ``R.random_element()``.

    OUTPUT:

    A quadratic form over the ring `R`.

    EXAMPLES::

        sage: random_quadraticform(ZZ, 3, [1,5])    ## RANDOM
        Quadratic form in 3 variables over Integer Ring with coefficients:
        [ 3 2 3 ]
        [ * 1 4 ]
        [ * * 3 ]

    ::

        sage: random_quadraticform(ZZ, 3, [-5,5])    ## RANDOM
        Quadratic form in 3 variables over Integer Ring with coefficients:
        [ 3 2 -5 ]
        [ * 2 -2 ]
        [ * * -5 ]

    ::

        sage: random_quadraticform(ZZ, 3, [-50,50])    ## RANDOM
        Quadratic form in 3 variables over Integer Ring with coefficients:
        [ 1 8 -23 ]
        [ * 0 0 ]
        [ * * 6 ]
    """
    ## Sanity Checks: We have a ring and there are at most 3 parameters for randomness!
    if len(rand_arg_list) > 3:
        raise TypeError(
            "Oops!  The list of randomness arguments can have at most 3 elements."
        )
    if not is_Ring(R):
        raise TypeError("Oops!  The first argument must be a ring.")

    ## Create a list of upper-triangular entries for the quadratic form
    L = len(rand_arg_list)
    nn = int(n * (n + 1) / 2)
    if L == 0:
        rand_list = [R.random_element() for _ in range(nn)]
    elif L == 1:
        rand_list = [R.random_element(rand_arg_list[0]) for _ in range(nn)]
    elif L == 2:
        rand_list = [
            R.random_element(rand_arg_list[0], rand_arg_list[1])
            for _ in range(nn)
        ]
    elif L == 3:
        rand_list = [
            R.random_element(rand_arg_list[0], rand_arg_list[1],
                             rand_arg_list[2]) for _ in range(nn)
        ]

    ## Return  the Quadratic Form
    return QuadraticForm(R, n, rand_list)
Esempio n. 14
0
def random_quadraticform(R, n, rand_arg_list=[]):
    """
    Create a random quadratic form in `n` variables defined over the ring `R`.

    The last (and optional) argument ``rand_arg_list`` is a list of at most 3
    elements which is passed (as at most 3 separate variables) into the method
    ``R.random_element()``.

    INPUT:

    - `R` -- a ring.
    - `n` -- an integer `\ge 0`
    - ``rand_arg_list`` -- a list of at most 3 arguments which can be taken by
      ``R.random_element()``.

    OUTPUT:

    A quadratic form over the ring `R`.

    EXAMPLES::
    
        sage: random_quadraticform(ZZ, 3, [1,5])    ## RANDOM
        Quadratic form in 3 variables over Integer Ring with coefficients:
        [ 3 2 3 ]
        [ * 1 4 ]
        [ * * 3 ]
    
    ::
        
        sage: random_quadraticform(ZZ, 3, [-5,5])    ## RANDOM
        Quadratic form in 3 variables over Integer Ring with coefficients:
        [ 3 2 -5 ]
        [ * 2 -2 ]
        [ * * -5 ]
        
    ::
        
        sage: random_quadraticform(ZZ, 3, [-50,50])    ## RANDOM
        Quadratic form in 3 variables over Integer Ring with coefficients:
        [ 1 8 -23 ]
        [ * 0 0 ]
        [ * * 6 ]
    """    
    ## Sanity Checks: We have a ring and there are at most 3 parameters for randomness!
    if len(rand_arg_list) > 3:
        raise TypeError, "Oops!  The list of randomness arguments can have at most 3 elements."
    if not is_Ring(R):
        raise TypeError, "Oops!  The first argument must be a ring."

    ## Create a list of upper-triangular entries for the quadratic form
    L = len(rand_arg_list)
    nn = int(n*(n+1)/2)
    if L == 0:
        rand_list = [R.random_element()  for _ in range(nn)]
    elif L == 1:
        rand_list = [R.random_element(rand_arg_list[0])  for _ in range(nn)]
    elif L == 2:
        rand_list = [R.random_element(rand_arg_list[0], rand_arg_list[1])  for _ in range(nn)]
    elif L == 3:
        rand_list = [R.random_element(rand_arg_list[0], rand_arg_list[1], rand_arg_list[2])  for _ in range(nn)]
                
    ## Return  the Quadratic Form
    return QuadraticForm(R, n, rand_list)
def LaurentPolynomialRing(base_ring, arg1=None, arg2=None, sparse = False, order='degrevlex', names = None, name=None):
    r"""
    Return the globally unique univariate or multivariate Laurent polynomial
    ring with given properties and variable name or names.

    There are four ways to call the Laurent polynomial ring constructor:

    1. ``LaurentPolynomialRing(base_ring, name,    sparse=False)``
    2. ``LaurentPolynomialRing(base_ring, names,   order='degrevlex')``
    3. ``LaurentPolynomialRing(base_ring, name, n, order='degrevlex')``
    4. ``LaurentPolynomialRing(base_ring, n, name, order='degrevlex')``

    The optional arguments sparse and order *must* be explicitly
    named, and the other arguments must be given positionally.

    INPUT:

    - ``base_ring`` -- a commutative ring
    - ``name`` -- a string
    - ``names`` -- a list or tuple of names, or a comma separated string
    - ``n`` -- a positive integer
    - ``sparse`` -- bool (default: False), whether or not elements are sparse
    - ``order`` -- string or
      :class:`~sage.rings.polynomial.term_order.TermOrder`, e.g.,

        - ``'degrevlex'`` (default) -- degree reverse lexicographic
        - ``'lex'`` -- lexicographic
        - ``'deglex'`` -- degree lexicographic
        - ``TermOrder('deglex',3) + TermOrder('deglex',3)`` -- block ordering

    OUTPUT:

    ``LaurentPolynomialRing(base_ring, name, sparse=False)`` returns a
    univariate Laurent polynomial ring; all other input formats return a
    multivariate Laurent polynomial ring.

    UNIQUENESS and IMMUTABILITY: In Sage there is exactly one
    single-variate Laurent polynomial ring over each base ring in each choice
    of variable and sparseness.  There is also exactly one multivariate
    Laurent polynomial ring over each base ring for each choice of names of
    variables and term order.

    ::

        sage: R.<x,y> = LaurentPolynomialRing(QQ,2); R
        Multivariate Laurent Polynomial Ring in x, y over Rational Field
        sage: f = x^2 - 2*y^-2

    You can't just globally change the names of those variables.
    This is because objects all over Sage could have pointers to
    that polynomial ring.

    ::

        sage: R._assign_names(['z','w'])
        Traceback (most recent call last):
        ...
        ValueError: variable names cannot be changed after object creation.


    EXAMPLES:

    1. ``LaurentPolynomialRing(base_ring, name, sparse=False)``

       ::

           sage: LaurentPolynomialRing(QQ, 'w')
           Univariate Laurent Polynomial Ring in w over Rational Field

       Use the diamond brackets notation to make the variable
       ready for use after you define the ring::

           sage: R.<w> = LaurentPolynomialRing(QQ)
           sage: (1 + w)^3
           1 + 3*w + 3*w^2 + w^3

       You must specify a name::

           sage: LaurentPolynomialRing(QQ)
           Traceback (most recent call last):
           ...
           TypeError: You must specify the names of the variables.

           sage: R.<abc> = LaurentPolynomialRing(QQ, sparse=True); R
           Univariate Laurent Polynomial Ring in abc over Rational Field

           sage: R.<w> = LaurentPolynomialRing(PolynomialRing(GF(7),'k')); R
           Univariate Laurent Polynomial Ring in w over Univariate Polynomial Ring in k over Finite Field of size 7

       Rings with different variables are different::

           sage: LaurentPolynomialRing(QQ, 'x') == LaurentPolynomialRing(QQ, 'y')
           False

    2. ``LaurentPolynomialRing(base_ring, names,   order='degrevlex')``

       ::

           sage: R = LaurentPolynomialRing(QQ, 'a,b,c'); R
           Multivariate Laurent Polynomial Ring in a, b, c over Rational Field

           sage: S = LaurentPolynomialRing(QQ, ['a','b','c']); S
           Multivariate Laurent Polynomial Ring in a, b, c over Rational Field

           sage: T = LaurentPolynomialRing(QQ, ('a','b','c')); T
           Multivariate Laurent Polynomial Ring in a, b, c over Rational Field

       All three rings are identical.

       ::

           sage: (R is S) and  (S is T)
           True

       There is a unique Laurent polynomial ring with each term order::

           sage: R = LaurentPolynomialRing(QQ, 'x,y,z', order='degrevlex'); R
           Multivariate Laurent Polynomial Ring in x, y, z over Rational Field
           sage: S = LaurentPolynomialRing(QQ, 'x,y,z', order='invlex'); S
           Multivariate Laurent Polynomial Ring in x, y, z over Rational Field
           sage: S is LaurentPolynomialRing(QQ, 'x,y,z', order='invlex')
           True
           sage: R == S
           False


    3. ``LaurentPolynomialRing(base_ring, name, n, order='degrevlex')``

       If you specify a single name as a string and a number of
       variables, then variables labeled with numbers are created.

       ::

           sage: LaurentPolynomialRing(QQ, 'x', 10)
           Multivariate Laurent Polynomial Ring in x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 over Rational Field

           sage: LaurentPolynomialRing(GF(7), 'y', 5)
           Multivariate Laurent Polynomial Ring in y0, y1, y2, y3, y4 over Finite Field of size 7

           sage: LaurentPolynomialRing(QQ, 'y', 3, sparse=True)
           Multivariate Laurent Polynomial Ring in y0, y1, y2 over Rational Field

       By calling the
       :meth:`~sage.structure.category_object.CategoryObject.inject_variables`
       method, all those variable names are available for interactive use::

           sage: R = LaurentPolynomialRing(GF(7),15,'w'); R
           Multivariate Laurent Polynomial Ring in w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14 over Finite Field of size 7
           sage: R.inject_variables()
           Defining w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14
           sage: (w0 + 2*w8 + w13)^2
           w0^2 + 4*w0*w8 + 4*w8^2 + 2*w0*w13 + 4*w8*w13 + w13^2
    """
    if is_Element(arg1) and not isinstance(arg1, (int, long, Integer)):
        arg1 = repr(arg1)
    if is_Element(arg2) and not isinstance(arg2, (int, long, Integer)):
        arg2 = repr(arg2)

    if isinstance(arg1, (int, long, Integer)):
        arg1, arg2 = arg2, arg1

    if not names is None:
        arg1 = names
    elif not name is None:
        arg1 = name

    if not is_Ring(base_ring):
        raise TypeError('base_ring must be a ring')

    if arg1 is None:
        raise TypeError("You must specify the names of the variables.")

    R = None
    if isinstance(arg1, (list, tuple)):
        arg1 = [str(x) for x in arg1]
    if isinstance(arg2, (list, tuple)):
        arg2 = [str(x) for x in arg2]
    if isinstance(arg2, (int, long, Integer)):
        # 3. LaurentPolynomialRing(base_ring, names, n, order='degrevlex'):
        if not isinstance(arg1, (list, tuple, str)):
            raise TypeError("You *must* specify the names of the variables.")
        n = int(arg2)
        names = arg1
        R = _multi_variate(base_ring, names, n, sparse, order)

    elif isinstance(arg1, str) or (isinstance(arg1, (list,tuple)) and len(arg1) == 1) and isinstance(arg1[0], str):
        if isinstance(arg1, (list,tuple)):
            arg1 = arg1[0]
        if not ',' in arg1:
            # 1. LaurentPolynomialRing(base_ring, name, sparse=False):
            if not arg2 is None:
                raise TypeError("if second arguments is a string with no commas, then there must be no other non-optional arguments")
            name = arg1
            R = _single_variate(base_ring, name, sparse)
        else:
            # 2-4. LaurentPolynomialRing(base_ring, names, order='degrevlex'):
            if not arg2 is None:
                raise TypeError("invalid input to LaurentPolynomialRing function; please see the docstring for that function")
            names = arg1.split(',')
            n = len(names)
            R = _multi_variate(base_ring, names, n, sparse, order)
    elif isinstance(arg1, (list, tuple)):
        # LaurentPolynomialRing(base_ring, names (list or tuple), order='degrevlex'):
        names = arg1
        n = len(names)
        R = _multi_variate(base_ring, names, n, sparse, order)

    if arg1 is None and arg2 is None:
        raise TypeError("you *must* specify the indeterminates (as not None).")
    if R is None:
        raise TypeError("invalid input (%s, %s, %s) to PolynomialRing function; please see the docstring for that function"%(base_ring, arg1, arg2))

    return R
Esempio n. 16
0
    def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, **kwds):
        """
        Return a ``UniqueFactory`` key and possibly extra parameters.

        INPUT:

        See the documentation for :class:`EllipticCurveFactory`.

        OUTPUT:

        A pair ``(key, extra_args)``:

        - ``key`` has the form `(R, (a_1, a_2, a_3, a_4, a_6))`,
          representing a ring and the Weierstrass coefficients of an
          elliptic curve over that ring;

        - ``extra_args`` is a dictionary containing additional data to
          be inserted into the elliptic curve structure.

        EXAMPLES::

            sage: EllipticCurve.create_key_and_extra_args(j=8000)
            ((Rational Field, (0, -1, 0, -3, -1)), {})

        When constructing a curve over `\\QQ` from a Cremona or LMFDB
        label, the invariants from the database are returned as
        ``extra_args``::

            sage: key, data = EllipticCurve.create_key_and_extra_args('389.a1')
            sage: key
            (Rational Field, (0, 1, 1, -2, 0))
            sage: data['conductor']
            389
            sage: data['cremona_label']
            '389a1'
            sage: data['lmfdb_label']
            '389.a1'
            sage: data['rank']
            2
            sage: data['torsion_order']
            1

        User-specified keywords are also included in ``extra_args``::

            sage: key, data = EllipticCurve.create_key_and_extra_args((0, 0, 1, -23737, 960366), rank=4)
            sage: data['rank']
            4

        Furthermore, keywords takes precedence over data from the
        database, which can be used to specify an alternative set of
        generators for the Mordell-Weil group::

            sage: key, data = EllipticCurve.create_key_and_extra_args('5077a1', gens=[[1, -1], [-2, 3], [4, -7]])
            sage: data['gens']
            [[1, -1], [-2, 3], [4, -7]]
            sage: E = EllipticCurve.create_object(0, key, **data)
            sage: E.gens()
            [(-2 : 3 : 1), (1 : -1 : 1), (4 : -7 : 1)]

        Note that elliptic curves are equal if and only they have the
        same base ring and Weierstrass equation; the data in
        ``extra_args`` do not influence comparison of elliptic curves.
        A consequence of this is that passing keyword arguments only
        works when constructing an elliptic curve the first time:

            sage: E = EllipticCurve('433a1', gens=[[-1, 1], [3, 4]])
            sage: E.gens()
            [(-1 : 1 : 1), (3 : 4 : 1)]
            sage: E = EllipticCurve('433a1', gens=[[-1, 0], [0, 1]])
            sage: E.gens()
            [(-1 : 1 : 1), (3 : 4 : 1)]

        .. WARNING::

            Manually specifying extra data is almost never necessary
            and is not guaranteed to have any effect, as the above
            example shows.  Almost no checking is done, so specifying
            incorrect data may lead to wrong results of computations
            instead of errors or warnings.

        """
        R = None
        if is_Ring(x):
            (R, x) = (x, y)

        if j is not None:
            if R is not None:
                try:
                    j = R(j)
                except (ZeroDivisionError, ValueError, TypeError):
                    raise ValueError("First parameter must be a ring containing %s" % j)
            elif x is not None:
                raise ValueError("First parameter (if present) must be a ring when j is specified")
            x = coefficients_from_j(j, minimal_twist)

        if is_SymbolicEquation(x):
            x = x.lhs() - x.rhs()

        if parent(x) is SR:
            x = x._polynomial_(rings.QQ['x', 'y'])

        if is_MPolynomial(x):
            if y is None:
                x = coefficients_from_Weierstrass_polynomial(x)
            else:
                x = coefficients_from_cubic(x, y, morphism=False)

        if isinstance(x, basestring):
            # Interpret x as a Cremona or LMFDB label.
            from sage.databases.cremona import CremonaDatabase
            x, data = CremonaDatabase().coefficients_and_data(x)
            # User-provided keywords may override database entries.
            data.update(kwds)
            kwds = data

        if not isinstance(x, (list, tuple)):
            raise TypeError("invalid input to EllipticCurve constructor")

        if len(x) == 2:
            x = (0, 0, 0, x[0], x[1])
        elif len(x) != 5:
            raise ValueError("sequence of coefficients must have length 2 or 5")

        if R is None:
            R = Sequence(x).universe()
            if R in (rings.ZZ, int, long):
                R = rings.QQ

        return (R, tuple(R(a) for a in x)), kwds
Esempio n. 17
0
    def create_key_and_extra_args(self,
                                  x=None,
                                  y=None,
                                  j=None,
                                  minimal_twist=True,
                                  **kwds):
        """
        Return a ``UniqueFactory`` key and possibly extra parameters.

        INPUT:

        See the documentation for :class:`EllipticCurveFactory`.

        OUTPUT:

        A pair ``(key, extra_args)``:

        - ``key`` has the form `(R, (a_1, a_2, a_3, a_4, a_6))`,
          representing a ring and the Weierstrass coefficients of an
          elliptic curve over that ring;

        - ``extra_args`` is a dictionary containing additional data to
          be inserted into the elliptic curve structure.

        EXAMPLES::

            sage: EllipticCurve.create_key_and_extra_args(j=8000)
            ((Rational Field, (0, -1, 0, -3, -1)), {})

        When constructing a curve over `\\QQ` from a Cremona or LMFDB
        label, the invariants from the database are returned as
        ``extra_args``::

            sage: key, data = EllipticCurve.create_key_and_extra_args('389.a1')
            sage: key
            (Rational Field, (0, 1, 1, -2, 0))
            sage: data['conductor']
            389
            sage: data['cremona_label']
            '389a1'
            sage: data['lmfdb_label']
            '389.a1'
            sage: data['rank']
            2
            sage: data['torsion_order']
            1

        User-specified keywords are also included in ``extra_args``::

            sage: key, data = EllipticCurve.create_key_and_extra_args((0, 0, 1, -23737, 960366), rank=4)
            sage: data['rank']
            4

        Furthermore, keywords takes precedence over data from the
        database, which can be used to specify an alternative set of
        generators for the Mordell-Weil group::

            sage: key, data = EllipticCurve.create_key_and_extra_args('5077a1', gens=[[1, -1], [-2, 3], [4, -7]])
            sage: data['gens']
            [[1, -1], [-2, 3], [4, -7]]
            sage: E = EllipticCurve.create_object(0, key, **data)
            sage: E.gens()
            [(-2 : 3 : 1), (1 : -1 : 1), (4 : -7 : 1)]

        Note that elliptic curves are equal if and only they have the
        same base ring and Weierstrass equation; the data in
        ``extra_args`` do not influence comparison of elliptic curves.
        A consequence of this is that passing keyword arguments only
        works when constructing an elliptic curve the first time::

            sage: E = EllipticCurve('433a1', gens=[[-1, 1], [3, 4]])
            sage: E.gens()
            [(-1 : 1 : 1), (3 : 4 : 1)]
            sage: E = EllipticCurve('433a1', gens=[[-1, 0], [0, 1]])
            sage: E.gens()
            [(-1 : 1 : 1), (3 : 4 : 1)]

        .. WARNING::

            Manually specifying extra data is almost never necessary
            and is not guaranteed to have any effect, as the above
            example shows.  Almost no checking is done, so specifying
            incorrect data may lead to wrong results of computations
            instead of errors or warnings.

        """
        R = None
        if is_Ring(x):
            (R, x) = (x, y)

        if j is not None:
            if R is not None:
                try:
                    j = R(j)
                except (ZeroDivisionError, ValueError, TypeError):
                    raise ValueError(
                        "First parameter must be a ring containing %s" % j)
            elif x is not None:
                raise ValueError(
                    "First parameter (if present) must be a ring when j is specified"
                )
            x = coefficients_from_j(j, minimal_twist)

        if is_SymbolicEquation(x):
            x = x.lhs() - x.rhs()

        if parent(x) is SR:
            x = x._polynomial_(rings.QQ['x', 'y'])

        if is_MPolynomial(x):
            if y is None:
                x = coefficients_from_Weierstrass_polynomial(x)
            else:
                x = coefficients_from_cubic(x, y, morphism=False)

        if isinstance(x, string_types):
            # Interpret x as a Cremona or LMFDB label.
            from sage.databases.cremona import CremonaDatabase
            x, data = CremonaDatabase().coefficients_and_data(x)
            # User-provided keywords may override database entries.
            data.update(kwds)
            kwds = data

        if not isinstance(x, (list, tuple)):
            raise TypeError("invalid input to EllipticCurve constructor")

        if len(x) == 2:
            x = (0, 0, 0, x[0], x[1])
        elif len(x) != 5:
            raise ValueError(
                "sequence of coefficients must have length 2 or 5")

        if R is None:
            R = Sequence(x).universe()
            if R in (rings.ZZ, ) + integer_types:
                R = rings.QQ

        return (R, tuple(R(a) for a in x)), kwds
Esempio n. 18
0
def EllipticCurve(x=None, y=None, j=None, minimal_twist=True):
    r"""
    Construct an elliptic curve.

    In Sage, an elliptic curve is always specified by its a-invariants

    .. math::

       y^2 + a_1 xy + a_3 y = x^3 + a_2 x^2 + a_4 x + a_6.

    INPUT:

    There are several ways to construct an elliptic curve:

    - ``EllipticCurve([a1,a2,a3,a4,a6])``: Elliptic curve with given
      a-invariants. The invariants are coerced into the parent of the
      first element. If all are integers, they are coerced into the
      rational numbers.

    - ``EllipticCurve([a4,a6])``: Same as above, but `a_1=a_2=a_3=0`.

    - ``EllipticCurve(label)``: Returns the elliptic curve over Q from
      the Cremona database with the given label. The label is a
      string, such as ``"11a"`` or ``"37b2"``. The letters in the
      label *must* be lower case (Cremona's new labeling).

    - ``EllipticCurve(R, [a1,a2,a3,a4,a6])``: Create the elliptic
      curve over ``R`` with given a-invariants. Here ``R`` can be an
      arbitrary ring. Note that addition need not be defined.

    - ``EllipticCurve(j=j0)`` or ``EllipticCurve_from_j(j0)``: Return
      an elliptic curve with j-invariant ``j0``.

    - ``EllipticCurve(polynomial)``: Read off the a-invariants from
      the polynomial coefficients, see
      :func:`EllipticCurve_from_Weierstrass_polynomial`.

    In each case above where the input is a list of length 2 or 5, one
    can instead give a 2 or 5-tuple instead.

    EXAMPLES:

    We illustrate creating elliptic curves::

        sage: EllipticCurve([0,0,1,-1,0])
        Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field

    We create a curve from a Cremona label::

        sage: EllipticCurve('37b2')
        Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field
        sage: EllipticCurve('5077a')
        Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field
        sage: EllipticCurve('389a')
        Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field

    Old Cremona labels are allowed::

        sage: EllipticCurve('2400FF')
        Elliptic Curve defined by y^2 = x^3 + x^2 + 2*x + 8 over Rational Field

    Unicode labels are allowed::

        sage: EllipticCurve(u'389a')
        Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field

    We create curves over a finite field as follows::

        sage: EllipticCurve([GF(5)(0),0,1,-1,0])
        Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5
        sage: EllipticCurve(GF(5), [0, 0,1,-1,0])
        Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5

    Elliptic curves over `\ZZ/N\ZZ` with `N` prime are of type
    "elliptic curve over a finite field"::

        sage: F = Zmod(101)
        sage: EllipticCurve(F, [2, 3])
        Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 101
        sage: E = EllipticCurve([F(2), F(3)])
        sage: type(E)
        <class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field_with_category'>
        sage: E.category()
        Category of schemes over Ring of integers modulo 101

    In contrast, elliptic curves over `\ZZ/N\ZZ` with `N` composite
    are of type "generic elliptic curve"::

        sage: F = Zmod(95)
        sage: EllipticCurve(F, [2, 3])
        Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 95
        sage: E = EllipticCurve([F(2), F(3)])
        sage: type(E)
        <class 'sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic_with_category'>
        sage: E.category()
        Category of schemes over Ring of integers modulo 95

    The following is a curve over the complex numbers::

        sage: E = EllipticCurve(CC, [0,0,1,-1,0])
        sage: E
        Elliptic Curve defined by y^2 + 1.00000000000000*y = x^3 + (-1.00000000000000)*x over Complex Field with 53 bits of precision
        sage: E.j_invariant()
        2988.97297297297

    We can also create elliptic curves by giving the Weierstrass equation::

        sage: x, y = var('x,y')
        sage: EllipticCurve(y^2 + y ==  x^3 + x - 9)
        Elliptic Curve defined by y^2 + y = x^3 + x - 9 over Rational Field

        sage: R.<x,y> = GF(5)[]
        sage: EllipticCurve(x^3 + x^2 + 2 - y^2 - y*x)
        Elliptic Curve defined by y^2 + x*y  = x^3 + x^2 + 2 over Finite Field of size 5

    We can explicitly specify the `j`-invariant::

        sage: E = EllipticCurve(j=1728); E; E.j_invariant(); E.label()
        Elliptic Curve defined by y^2 = x^3 - x over Rational Field
        1728
        '32a2'

        sage: E = EllipticCurve(j=GF(5)(2)); E; E.j_invariant()
        Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5
        2

    See :trac:`6657` ::

        sage: EllipticCurve(GF(144169),j=1728)
        Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 144169

    By default, when a rational value of `j` is given, the constructed
    curve is a minimal twist (minimal conductor for curves with that
    `j`-invariant).  This can be changed by setting the optional
    parameter ``minimal_twist``, which is True by default, to False::


        sage: EllipticCurve(j=100)
        Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field
        sage: E =EllipticCurve(j=100); E
        Elliptic Curve defined by y^2 = x^3 + x^2 + 3392*x + 307888 over Rational Field
        sage: E.conductor()
        33129800
        sage: E.j_invariant()
        100
        sage: E =EllipticCurve(j=100, minimal_twist=False); E
        Elliptic Curve defined by y^2 = x^3 + 488400*x - 530076800 over Rational Field
        sage: E.conductor()
        298168200
        sage: E.j_invariant()
        100

    Without this option, constructing the curve could take a long time
    since both `j` and `j-1728` have to be factored to compute the
    minimal twist (see :trac:`13100`)::

       sage: E = EllipticCurve_from_j(2^256+1,minimal_twist=False)
       sage: E.j_invariant() == 2^256+1
       True

    TESTS::

        sage: R = ZZ['u', 'v']
        sage: EllipticCurve(R, [1,1])
        Elliptic Curve defined by y^2 = x^3 + x + 1 over Multivariate Polynomial Ring in u, v
        over Integer Ring

    We create a curve and a point over QQbar (see #6879)::

        sage: E = EllipticCurve(QQbar,[0,1])
        sage: E(0)
        (0 : 1 : 0)
        sage: E.base_field()
        Algebraic Field

        sage: E = EllipticCurve(RR,[1,2]); E; E.base_field()
        Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision
        Real Field with 53 bits of precision
        sage: EllipticCurve(CC,[3,4]); E; E.base_field()
        Elliptic Curve defined by y^2 = x^3 + 3.00000000000000*x + 4.00000000000000 over Complex Field with 53 bits of precision
        Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 2.00000000000000 over Real Field with 53 bits of precision
        Real Field with 53 bits of precision
        sage: E = EllipticCurve(QQbar,[5,6]); E; E.base_field()
        Elliptic Curve defined by y^2 = x^3 + 5*x + 6 over Algebraic Field
        Algebraic Field

    See :trac:`6657` ::

        sage: EllipticCurve(3,j=1728)
        Traceback (most recent call last):
        ...
        ValueError: First parameter (if present) must be a ring when j is specified

        sage: EllipticCurve(GF(5),j=3/5)
        Traceback (most recent call last):
        ...
        ValueError: First parameter must be a ring containing 3/5

    If the universe of the coefficients is a general field, the object
    constructed has type EllipticCurve_field.  Otherwise it is
    EllipticCurve_generic.  See :trac:`9816` ::

        sage: E = EllipticCurve([QQbar(1),3]); E
        Elliptic Curve defined by y^2 = x^3 + x + 3 over Algebraic Field
        sage: type(E)
        <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'>

        sage: E = EllipticCurve([RR(1),3]); E
        Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 3.00000000000000 over Real Field with 53 bits of precision
        sage: type(E)
        <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'>

        sage: E = EllipticCurve([i,i]); E
        Elliptic Curve defined by y^2 = x^3 + I*x + I over Symbolic Ring
        sage: type(E)
        <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'>
        sage: E.category()
        Category of schemes over Symbolic Ring
        sage: SR in Fields()
        True

        sage: F = FractionField(PolynomialRing(QQ,'t'))
        sage: t = F.gen()
        sage: E = EllipticCurve([t,0]); E
        Elliptic Curve defined by y^2 = x^3 + t*x over Fraction Field of Univariate Polynomial Ring in t over Rational Field
        sage: type(E)
        <class 'sage.schemes.elliptic_curves.ell_field.EllipticCurve_field_with_category'>
        sage: E.category()
        Category of schemes over Fraction Field of Univariate Polynomial Ring in t over Rational Field

    See :trac:`12517`::

        sage: E = EllipticCurve([1..5])
        sage: EllipticCurve(E.a_invariants())
        Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field

    See :trac:`11773`::

        sage: E = EllipticCurve()
        Traceback (most recent call last):
        ...
        TypeError: invalid input to EllipticCurve constructor

    """
    import ell_generic, ell_field, ell_finite_field, ell_number_field, ell_rational_field, ell_padic_field  # here to avoid circular includes

    if j is not None:
        if not x is None:
            if is_Ring(x):
                try:
                    j = x(j)
                except (ZeroDivisionError, ValueError, TypeError):
                    raise ValueError, "First parameter must be a ring containing %s" % j
            else:
                raise ValueError, "First parameter (if present) must be a ring when j is specified"
        return EllipticCurve_from_j(j, minimal_twist)

    if x is None:
        raise TypeError, "invalid input to EllipticCurve constructor"

    if is_SymbolicEquation(x):
        x = x.lhs() - x.rhs()

    if parent(x) is SR:
        x = x._polynomial_(rings.QQ['x', 'y'])

    if is_MPolynomial(x):
        if y is None:
            return EllipticCurve_from_Weierstrass_polynomial(x)
        else:
            return EllipticCurve_from_cubic(x, y, morphism=False)

    if is_Ring(x):
        if is_RationalField(x):
            return ell_rational_field.EllipticCurve_rational_field(x, y)
        elif is_FiniteField(x) or (is_IntegerModRing(x)
                                   and x.characteristic().is_prime()):
            return ell_finite_field.EllipticCurve_finite_field(x, y)
        elif rings.is_pAdicField(x):
            return ell_padic_field.EllipticCurve_padic_field(x, y)
        elif is_NumberField(x):
            return ell_number_field.EllipticCurve_number_field(x, y)
        elif x in _Fields:
            return ell_field.EllipticCurve_field(x, y)
        return ell_generic.EllipticCurve_generic(x, y)

    if isinstance(x, unicode):
        x = str(x)

    if isinstance(x, basestring):
        return ell_rational_field.EllipticCurve_rational_field(x)

    if is_RingElement(x) and y is None:
        raise TypeError, "invalid input to EllipticCurve constructor"

    if not isinstance(x, (list, tuple)):
        raise TypeError, "invalid input to EllipticCurve constructor"

    x = Sequence(x)
    if not (len(x) in [2, 5]):
        raise ValueError, "sequence of coefficients must have length 2 or 5"
    R = x.universe()

    if isinstance(x[0], (rings.Rational, rings.Integer, int, long)):
        return ell_rational_field.EllipticCurve_rational_field(x, y)

    elif is_NumberField(R):
        return ell_number_field.EllipticCurve_number_field(x, y)

    elif rings.is_pAdicField(R):
        return ell_padic_field.EllipticCurve_padic_field(x, y)

    elif is_FiniteField(R) or (is_IntegerModRing(R)
                               and R.characteristic().is_prime()):
        return ell_finite_field.EllipticCurve_finite_field(x, y)

    elif R in _Fields:
        return ell_field.EllipticCurve_field(x, y)

    return ell_generic.EllipticCurve_generic(x, y)