Example #1
0
def _multi_variate(base_ring, num_gens=None, names=None,
                     order='negdeglex', default_prec=None, sparse=False):
    """
    Construct multivariate power series ring.
    """
    if names is None:
        raise TypeError("you must specify a variable name or names")

    if num_gens is None:
        if isinstance(names,str):
            num_gens = len(names.split(','))
        elif isinstance(names, (list, tuple)):
            num_gens = len(names)
        else:
            raise TypeError("variable names must be a string, tuple or list")
    names = normalize_names(num_gens, names)
    num_gens = len(names)
    if default_prec is None:
        default_prec = 12

    if base_ring not in commutative_rings.CommutativeRings():
        raise TypeError("base_ring must be a commutative ring")
    from sage.rings.multi_power_series_ring import MPowerSeriesRing_generic
    R = MPowerSeriesRing_generic(base_ring, num_gens, names,
                                 order=order, default_prec=default_prec, sparse=sparse)
    return R
Example #2
0
def AffineSpace(n, R=None, names='x'):
    r"""
    Return affine space of dimension ``n`` over the ring ``R``.

    EXAMPLES:

    The dimension and ring can be given in either order::

        sage: AffineSpace(3, QQ, 'x')
        Affine Space of dimension 3 over Rational Field
        sage: AffineSpace(5, QQ, 'x')
        Affine Space of dimension 5 over Rational Field
        sage: A = AffineSpace(2, QQ, names='XY'); A
        Affine Space of dimension 2 over Rational Field
        sage: A.coordinate_ring()
        Multivariate Polynomial Ring in X, Y over Rational Field

    Use the divide operator for base extension::

        sage: AffineSpace(5, names='x')/GF(17)
        Affine Space of dimension 5 over Finite Field of size 17

    The default base ring is `\ZZ`::

        sage: AffineSpace(5, names='x')
        Affine Space of dimension 5 over Integer Ring

    There is also an affine space associated to each polynomial ring::

        sage: R = GF(7)['x, y, z']
        sage: A = AffineSpace(R); A
        Affine Space of dimension 3 over Finite Field of size 7
        sage: A.coordinate_ring() is R
        True
    """
    if (is_MPolynomialRing(n) or is_PolynomialRing(n)) and R is None:
        R = n
        A = AffineSpace(R.ngens(), R.base_ring(), R.variable_names())
        A._coordinate_ring = R
        return A
    if isinstance(R, integer_types + (Integer,)):
        n, R = R, n
    if R is None:
        R = ZZ  # default is the integers
    if names is None:
        if n == 0:
            names = ''
        else:
            raise TypeError("you must specify the variables names of the coordinate ring")
    names = normalize_names(n, names)
    if R in _Fields:
        if is_FiniteField(R):
            return AffineSpace_finite_field(n, R, names)
        else:
            return AffineSpace_field(n, R, names)
    return AffineSpace_generic(n, R, names)
def _single_variate(base_ring, name, sparse, implementation):
    import sage.rings.polynomial.polynomial_ring as m
    name = normalize_names(1, name)
    key = (base_ring, name, sparse, implementation if not sparse else None)
    R = _get_from_cache(key)
    if not R is None:
        return R

    if isinstance(base_ring, ring.CommutativeRing):
        if is_IntegerModRing(base_ring) and not sparse:
            n = base_ring.order()
            if n.is_prime():
                R = m.PolynomialRing_dense_mod_p(base_ring, name, implementation=implementation)
            elif n > 1:
                R = m.PolynomialRing_dense_mod_n(base_ring, name, implementation=implementation)
            else:  # n == 1!
                R = m.PolynomialRing_integral_domain(base_ring, name)   # specialized code breaks in this case.

        elif is_FiniteField(base_ring) and not sparse:
            R = m.PolynomialRing_dense_finite_field(base_ring, name, implementation=implementation)

        elif isinstance(base_ring, padic_base_leaves.pAdicFieldCappedRelative):
            R = m.PolynomialRing_dense_padic_field_capped_relative(base_ring, name)

        elif isinstance(base_ring, padic_base_leaves.pAdicRingCappedRelative):
            R = m.PolynomialRing_dense_padic_ring_capped_relative(base_ring, name)

        elif isinstance(base_ring, padic_base_leaves.pAdicRingCappedAbsolute):
            R = m.PolynomialRing_dense_padic_ring_capped_absolute(base_ring, name)

        elif isinstance(base_ring, padic_base_leaves.pAdicRingFixedMod):
            R = m.PolynomialRing_dense_padic_ring_fixed_mod(base_ring, name)

        elif base_ring in _CompleteDiscreteValuationRings:
            R = m.PolynomialRing_cdvr(base_ring, name, sparse)

        elif base_ring in _CompleteDiscreteValuationFields:
            R = m.PolynomialRing_cdvf(base_ring, name, sparse)

        elif base_ring.is_field(proof = False):
            R = m.PolynomialRing_field(base_ring, name, sparse)

        elif base_ring.is_integral_domain(proof = False):
            R = m.PolynomialRing_integral_domain(base_ring, name, sparse, implementation)
        else:
            R = m.PolynomialRing_commutative(base_ring, name, sparse)
    else:
        R = m.PolynomialRing_general(base_ring, name, sparse)

    if hasattr(R, '_implementation_names'):
        for name in R._implementation_names:
            real_key = key[0:3] + (name,)
            _save_in_cache(real_key, R)
    else:
        _save_in_cache(key, R)
    return R
Example #4
0
    def __init__(self, n, R=ZZ, names=None):
        """
        EXAMPLES::

            sage: ProjectiveSpace(3, Zp(5), 'y')
            Projective Space of dimension 3 over 5-adic Ring with capped relative precision 20
        """
        names = normalize_names(n+1, names)
        AmbientSpace.__init__(self, n, R)
        self._assign_names(names)
Example #5
0
    def __init__(self, G, names, base_ring):
        """
        The Python constructor

        EXAMPLES::

            sage: F = AbelianGroup(5,[3,5,7,8,9], names="abcde")
            sage: F.dual_group()
            Dual of Abelian Group isomorphic to Z/3Z x Z/5Z x Z/7Z x Z/8Z x Z/9Z
            over Cyclotomic Field of order 2520 and degree 576
       """
        self._base_ring = base_ring
        self._group = G
        names = normalize_names(G.ngens(), names)
        self._assign_names(names)
        AbelianGroupBase.__init__(self) # TODO: category=CommutativeGroups()
Example #6
0
def FreeAbelianMonoid(index_set=None, names=None, **kwds):
    """
    Return a free abelian monoid on `n` generators or with the generators
    indexed by a set `I`.

    We construct free abelian monoids by specifing either:

    - the number of generators and/or the names of the generators
    - the indexing set for the generators (this ignores the other two inputs)

    INPUT:

    - ``index_set`` -- an indexing set for the generators; if an integer,
      then this becomes `\{0, 1, \ldots, n-1\}`

    -  ``names`` -- names of generators

    OUTPUT:

    A free abelian monoid.

    EXAMPLES::

        sage: F.<a,b,c,d,e> = FreeAbelianMonoid(); F
        Free abelian monoid on 5 generators (a, b, c, d, e)
        sage: FreeAbelianMonoid(index_set=ZZ)
        Free abelian monoid indexed by Integer Ring
    """
    if isinstance(index_set, str): # Swap args (this works if names is None as well)
        names, index_set = index_set, names

    if index_set is None and names is not None:
        if isinstance(names, str):
            index_set = names.count(',')
        else:
            index_set = len(names)

    if index_set not in ZZ:
        if names is not None:
            names = normalize_names(len(names), names)
        from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid
        return IndexedFreeAbelianMonoid(index_set, names=names, **kwds)

    if names is None:
        raise ValueError("names must be specified")
    return FreeAbelianMonoid_factory(index_set, names)
def _multi_variate(base_ring, names, n, sparse, order, implementation):
#    if not sparse:
#        raise ValueError, "A dense representation of multivariate polynomials is not supported"
    sparse = False
    # "True" would be correct, since there is no dense implementation of
    # multivariate polynomials. However, traditionally, "False" is used in the key,
    # even though it is meaningless.

    if implementation is not None:
        raise ValueError("The %s implementation is not known for multivariate polynomial rings"%implementation)

    names = normalize_names(n, names)
    n = len(names)

    import sage.rings.polynomial.multi_polynomial_ring as m
    from sage.rings.polynomial.term_order import TermOrder

    order = TermOrder(order, n)

    key = (base_ring, names, n, sparse, order)
    R = _get_from_cache(key)
    if not R is None:
        return R

    from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular
    if isinstance(base_ring, ring.IntegralDomain):
        if n < 1:
            R = m.MPolynomialRing_polydict_domain(base_ring, n, names, order)
        else:
            try:
                R = MPolynomialRing_libsingular(base_ring, n, names, order)
            except ( TypeError, NotImplementedError ):
                R = m.MPolynomialRing_polydict_domain(base_ring, n, names, order)
    else:
        if not base_ring.is_zero():
            try:
                R = MPolynomialRing_libsingular(base_ring, n, names, order)
            except ( TypeError, NotImplementedError ):
                R = m.MPolynomialRing_polydict(base_ring, n, names, order)
        else:
            R = m.MPolynomialRing_polydict(base_ring, n, names, order)
    _save_in_cache(key, R)
    return R
def _multi_variate(base_ring, names, n, sparse, order):
    """
    EXAMPLES::

        sage: from sage.rings.polynomial.laurent_polynomial_ring import _multi_variate
        sage: _multi_variate(QQ, ('x','y'), 2, False, 'degrevlex')
        Multivariate Laurent Polynomial Ring in x, y over Rational Field
    """
    # We need to come up with a name for the inverse that is easy to search
    # for in a string *and* doesn't overlap with the name that we already have.
    # For now, I'm going to use a name mangling with checking method.
    names = normalize_names(n, names)

    from term_order import TermOrder
    order = TermOrder(order, n)

    if isinstance(names, list):
        names = tuple(names)
    elif isinstance(names, str):
        if ',' in names:
            names = tuple(names.split(','))

    key = (base_ring, names, n, sparse, order)
    P = _get_from_cache(key)
    if P is not None:
        return P
    prepend_string = "qk"
    while True:
        for a in names:
            if prepend_string in a:
                prepend_string += 'k'
                break
        else:
            break
    R = _multi_variate_poly(base_ring, names, n, sparse, order, None)
    P = LaurentPolynomialRing_mpair(R, prepend_string, names)
    _save_in_cache(key, P)
    return P
def _single_variate(base_ring, names, sparse):
    """
    EXAMPLES::

        sage: from sage.rings.polynomial.laurent_polynomial_ring import _single_variate
        sage: _single_variate(QQ, ('x',), False)
        Univariate Laurent Polynomial Ring in x over Rational Field
    """
    names = normalize_names(1, names)
    key = (base_ring, names, sparse)
    P = _get_from_cache(key)
    if P is not None:
        return P
    prepend_string = "qk"
    while True:
        if prepend_string in names:
            prepend_string += 'k'
        else:
            break
    R = _single_variate_poly(base_ring, names, sparse, None)
    P = LaurentPolynomialRing_univariate(R, names)
    _save_in_cache(key, P)
    return P
Example #10
0
 def __init__(self, PP, f, h=None, names=None, genus=None):
     x, y, z = PP.gens()
     df = f.degree()
     F1 = sum([ f[i]*x**i*z**(df-i) for i in range(df+1) ])
     if h is None:
         F = y**2*z**(df-2) - F1
     else:
         dh = h.degree()
         deg = max(df,dh+1)
         F0 = sum([ h[i]*x**i*z**(dh-i) for i in range(dh+1) ])
         F = y**2*z**(deg-2) + F0*y*z**(deg-dh-1) - F1*z**(deg-df)
     plane_curve.ProjectiveCurve_generic.__init__(self,PP,F)
     R = PP.base_ring()
     if names is None:
         names = ("x", "y")
     else:
         names = normalize_names(2, names)
     self._names = names
     P1 = PolynomialRing(R, name=names[0])
     P2 = PolynomialRing(P1, name=names[1])
     self._PP = PP
     self._printing_ring = P2
     self._hyperelliptic_polynomials = (f,h)
     self._genus = genus
Example #11
0
    def __classcall_private__(cls,
                              universe,
                              *predicates,
                              vars=None,
                              names=None,
                              category=None):
        r"""
        Normalize init arguments.

        TESTS::

            sage: ConditionSet(ZZ, names=["x"]) is ConditionSet(ZZ, names=x)
            True
            sage: ConditionSet(RR, x > 0, names=x) is ConditionSet(RR, (x > 0).function(x))
            True
        """
        if category is None:
            category = Sets()
        if isinstance(universe, Parent):
            if universe in Sets().Finite():
                category &= Sets().Finite()
            if universe in EnumeratedSets():
                category &= EnumeratedSets()

        if vars is not None:
            if names is not None:
                raise ValueError(
                    'cannot use names and vars at the same time; they are aliases'
                )
            names, vars = vars, None

        if names is not None:
            names = normalize_names(-1, names)

        callable_symbolic_predicates = []
        other_predicates = []

        for predicate in predicates:
            if isinstance(predicate, Expression) and predicate.is_callable():
                if names is None:
                    names = tuple(str(var) for var in predicate.args())
                elif len(names) != len(predicate.args()):
                    raise TypeError('mismatch in number of arguments')
                if vars is None:
                    vars = predicate.args()
                callable_symbolic_predicates.append(predicate)
            elif isinstance(predicate, Expression):
                if names is None:
                    raise TypeError(
                        'use callable symbolic expressions or provide variable names'
                    )
                if vars is None:
                    from sage.symbolic.ring import SR
                    vars = tuple(SR.var(name) for name in names)
                callable_symbolic_predicates.append(predicate.function(*vars))
            else:
                other_predicates.append(predicate)

        predicates = list(
            _stable_uniq(callable_symbolic_predicates + other_predicates))

        if not other_predicates and not callable_symbolic_predicates:
            if names is None and category is None:
                # No conditions, no variable names, no category, just use Set.
                return Set(universe)

        if any(predicate.args() != vars
               for predicate in callable_symbolic_predicates):
            # TODO: Implement safe renaming of the arguments of a callable symbolic expressions
            raise NotImplementedError(
                'all callable symbolic expressions must use the same arguments'
            )

        if names is None:
            names = ("x", )
        return super().__classcall__(cls,
                                     universe,
                                     *predicates,
                                     names=names,
                                     category=category)
Example #12
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)
Example #13
0
def ProductProjectiveSpaces(n, R=None, names='x'):
    r"""
    Returns the Cartesian product of projective spaces.

    Can input either a list of projective space over the same base \
    ring or the list of dimensions, the base ring, and the variable names.

    INPUT:

    - ``n`` -- a list of integers or a list of projective spaces.

    - ``R`` -- a ring.

    - ``names`` -- a string or list of strings.

    EXAMPLES::

        sage: P1 = ProjectiveSpace(QQ, 2, 'x')
        sage: P2 = ProjectiveSpace(QQ, 3, 'y')
        sage: ProductProjectiveSpaces([P1, P2])
        Product of projective spaces P^2 x P^3 over Rational Field

    ::

        sage: ProductProjectiveSpaces([2, 2],GF(7), 'y')
        Product of projective spaces P^2 x P^2 over Finite Field of size 7

    ::

        sage: P1 = ProjectiveSpace(ZZ, 2, 'x')
        sage: P2 = ProjectiveSpace(QQ, 3, 'y')
        sage: ProductProjectiveSpaces([P1, P2])
        Traceback (most recent call last):
        ...
        AttributeError: components must be over the same base ring
    """
    if isinstance(R, (list, tuple)):
        n, R = R, n
    if not isinstance(n, (tuple, list)):
        raise TypeError("must be a list of dimensions")
    if R is None:
        R = QQ  # default is the rationals
    if isinstance(n[0], ProjectiveSpace_ring):
        #this should be a list of projective spaces
        names = []
        N = []
        R = None
        for PS in n:
            if not isinstance(PS, ProjectiveSpace_ring):
                raise TypeError(
                    "must be a list of projective spaces or (dimensions, base ring, names)"
                )
            if R is None:
                R = PS.base_ring()
            elif R != PS.base_ring():
                raise AttributeError(
                    "components must be over the same base ring")
            N.append(PS.dimension_relative())
            names += PS.variable_names()
        if is_FiniteField(R):
            X = ProductProjectiveSpaces_finite_field(N, R, names)
        elif R in Fields():
            X = ProductProjectiveSpaces_field(N, R, names)
        else:
            X = ProductProjectiveSpaces_ring(N, R, names)
        X._components = n
    else:
        if not isinstance(n, (list, tuple)):
            raise ValueError("need list or tuple of dimensions")
        if not isinstance(R, CommutativeRing):
            raise ValueError("must be a commutative ring")
        from sage.structure.category_object import normalize_names
        n_vars = sum(d + 1 for d in n)
        if isinstance(names, six.string_types):
            names = normalize_names(n_vars, names)
        else:
            name_list = list(names)
            if len(name_list) == len(n):
                names = []
                for name, dim in zip(name_list, n):
                    names += normalize_names(dim + 1, name)
            else:
                n_vars = sum(1 + d for d in n)
                names = normalize_names(n_vars, name_list)
        if is_FiniteField(R):
            X = ProductProjectiveSpaces_finite_field(n, R, names)
        elif R in Fields():
            X = ProductProjectiveSpaces_field(n, R, names)
        else:
            X = ProductProjectiveSpaces_ring(n, R, names)
    return X
Example #14
0
    def __init__(self,
                 monic_polynomial,
                 names='X',
                 iterate=True,
                 warning=True):
        r"""
        Python constructor.

        EXAMPLES::

            sage: from sage.algebras.splitting_algebra import SplittingAlgebra
            sage: Lw.<w> = LaurentPolynomialRing(ZZ)
            sage: PuvLw.<u,v> = Lw[]; t = polygen(PuvLw)
            sage: S.<x, y> = SplittingAlgebra(t^3 - u*t^2 + v*t - w, warning=False)
            sage: TestSuite(S).run()
        """

        # ---------------------------------------------------------------------------------
        # checking input parameters
        # ---------------------------------------------------------------------------------

        base_ring = monic_polynomial.base_ring()
        if not monic_polynomial.is_monic():
            raise ValueError("given polynomial must be monic")
        deg = monic_polynomial.degree()

        from sage.structure.category_object import normalize_names
        self._root_names = normalize_names(deg - 1, names)
        root_names = list(self._root_names)
        verbose(
            "Create splitting algebra to base ring %s and polynomial %s (%s %s)"
            % (base_ring, monic_polynomial, iterate, warning))

        self._defining_polynomial = monic_polynomial
        self._iterate = iterate

        try:
            if not base_ring.is_integral_domain():
                raise TypeError("base_ring must be an integral domain")
        except NotImplementedError:
            from sage.rings.ring import Ring
            if not isinstance(base_ring, Ring):
                raise TypeError("base_ring must be an instance of ring")
            if warning:
                warn('Assuming %s to be an integral domain!' % (base_ring))

        if deg < 1:
            raise ValueError("the degree of the polynomial must positive")

        self._splitting_roots = []
        self._coefficients_list = []
        self._invertible_elements = {}

        if isinstance(base_ring, SplittingAlgebra):
            self._invertible_elements = base_ring._invertible_elements

        # ------------------------------------------------------------------------------------
        # taking next root_name
        # ------------------------------------------------------------------------------------
        root_name = root_names[0]
        p = monic_polynomial.change_variable_name(root_name)
        P = p.parent()

        self._set_modulus_irreducible_ = False
        try:
            if not p.is_irreducible():
                raise ValueError("monic_polynomial must be irreducible")
        except (NotImplementedError, AttributeError):
            # assuming this has been checked mathematically before
            self._set_modulus_irreducible_ = True
            if warning:
                warn('Asuming %s to have maximal Galois group!' %
                     (monic_polynomial))
                warning = False  # one warning must be enough

        verbose("P %s defined:" % (P))

        if deg > 2 and iterate:
            # ------------------------------------------------------------------------------------
            # successive solution via recursion (on base_ring_step)
            # ------------------------------------------------------------------------------------
            base_ring_step = SplittingAlgebra(monic_polynomial,
                                              tuple(root_names),
                                              iterate=False,
                                              warning=False)
            first_root = base_ring_step.gen()

            verbose("base_ring_step %s defined:" % (base_ring_step))

            # ------------------------------------------------------------------------------------
            # splitting first root off
            # ------------------------------------------------------------------------------------
            from copy import copy
            root_names_reduces = copy(root_names)
            root_names_reduces.remove(root_name)

            P = base_ring_step[root_names_reduces[0]]
            p = P(monic_polynomial.dict())
            q, r = p.quo_rem((P.gen() - first_root))

            verbose("Invoking recursion with: %s" % (q, ))

            SplittingAlgebra.__init__(self,
                                      q,
                                      root_names_reduces,
                                      warning=False)

            splitting_roots = base_ring_step._splitting_roots + self._splitting_roots
            coefficients_list = base_ring_step._coefficients_list + self._coefficients_list

            verbose("Adding roots: %s" % (splitting_roots))

            self._splitting_roots = splitting_roots
            self._coefficients_list = coefficients_list
        else:
            PolynomialQuotientRing_domain.__init__(self, P, p, root_name)

            first_root = self.gen()
            self._splitting_roots.append(first_root)
            self._coefficients_list = [
                monic_polynomial.coefficients(sparse=False)
            ]

            if not iterate:
                verbose("pre ring defined splitting_roots: %s" %
                        (self._splitting_roots))
                return

            verbose("final ring defined splitting_roots: %s" %
                    (self._splitting_roots))

        if deg == 2:
            coefficients = monic_polynomial.coefficients(sparse=False)
            lin_coeff = coefficients[1]
            self._splitting_roots.append(-lin_coeff - first_root)

        self._root_names = names
        self._splitting_roots = [self(root) for root in self._splitting_roots]
        verbose("splitting_roots: %s embedded" % (self._splitting_roots))

        # -------------------------------------------------------------------------------------------
        # try to calculate inverses of the roots. This is possible if the original polynomial
        # has an invertible constant term. For example let cf = [-w, v,-u, 1] that is
        # p = h^3 -u*h^2 + v*h -w, than u = x + y + z, v = x*y + x*z + y*z, w = x*y*z. If
        # w is invertible then 1/x = (v -(u-x)*x)/w, 1/y = (v -(u-y)*y)/w, 1/z = (v -(u-z)*z)/w
        # -------------------------------------------------------------------------------------------
        # first find the polynomial with invertible constant coefficient
        # -------------------------------------------------------------------------------------------
        cf0_inv = None
        for cf in self._coefficients_list:
            cf0 = cf[0]
            try:
                cf0_inv = ~(cf[0])
                cf0_inv = self(cf0_inv)
                verbose("invertible coefficient: %s found" % (cf0_inv))
                break
            except NotImplementedError:
                verbose("constant coefficient: %s not invertibe" % (cf0))

        # ----------------------------------------------------------------------------------
        # assuming that cf splits into linear factors over self and the _splitting_roots
        # are its roots we can calculate inverses
        # ----------------------------------------------------------------------------------
        if cf0_inv is not None:
            deg_cf = len(cf) - 1
            pf = P(cf)
            for root in self._splitting_roots:
                check = self(pf)
                if not check.is_zero():
                    continue
                root_inv = self.one()
                for pos in range(deg_cf - 1):
                    root_inv = (-1)**(pos + 1) * cf[deg_cf - pos -
                                                    1] - root_inv * root
                verbose("inverse %s of root %s" % (root_inv, root))
                root_inv = (-1)**(deg_cf) * cf0_inv * root_inv
                self._invertible_elements.update({root: root_inv})
                verbose("adding inverse %s of root %s" % (root_inv, root))
            invert_items = [(k, v)
                            for k, v in self._invertible_elements.items()]
            for k, v in invert_items:
                self._invertible_elements.update({v: k})
        return
Example #15
0
def QuotientRing(R, I, names=None):
    r"""
    Creates a quotient ring of the ring `R` by the twosided ideal `I`.

    Variables are labeled by ``names`` (if the quotient ring is a quotient
    of a polynomial ring).  If ``names`` isn't given, 'bar' will be appended
    to the variable names in `R`.

    INPUT:

    - ``R`` -- a ring.

    - ``I`` -- a twosided ideal of `R`.

    - ``names`` -- (optional) a list of strings to be used as names for
      the variables in the quotient ring `R/I`.

    OUTPUT: `R/I` - the quotient ring `R` mod the ideal `I`

    ASSUMPTION:

    ``I`` has a method ``I.reduce(x)`` returning the normal form
    of elements `x\in R`. In other words, it is required that
    ``I.reduce(x)==I.reduce(y)`` `\iff x-y \in I`, and
    ``x-I.reduce(x) in I``, for all `x,y\in R`.

    EXAMPLES:

    Some simple quotient rings with the integers::

        sage: R = QuotientRing(ZZ,7*ZZ); R
        Quotient of Integer Ring by the ideal (7)
        sage: R.gens()
        (1,)
        sage: 1*R(3); 6*R(3); 7*R(3)
        3
        4
        0

    ::

        sage: S = QuotientRing(ZZ,ZZ.ideal(8)); S
        Quotient of Integer Ring by the ideal (8)
        sage: 2*S(4)
        0

    With polynomial rings (note that the variable name of the quotient
    ring can be specified as shown below)::

        sage: R.<xx> = QuotientRing(QQ[x], QQ[x].ideal(x^2 + 1)); R
        Univariate Quotient Polynomial Ring in xx over Rational Field with modulus x^2 + 1
        sage: R.gens(); R.gen()
        (xx,)
        xx
        sage: for n in range(4): xx^n
        1
        xx
        -1
        -xx

    ::

        sage: S = QuotientRing(QQ[x], QQ[x].ideal(x^2 - 2)); S
        Univariate Quotient Polynomial Ring in xbar over Rational Field with
        modulus x^2 - 2
        sage: xbar = S.gen(); S.gen()
        xbar
        sage: for n in range(3): xbar^n
        1
        xbar
        2

    Sage coerces objects into ideals when possible::

        sage: R = QuotientRing(QQ[x], x^2 + 1); R
        Univariate Quotient Polynomial Ring in xbar over Rational Field with
        modulus x^2 + 1

    By Noether's homomorphism theorems, the quotient of a quotient ring
    of `R` is just the quotient of `R` by the sum of the ideals. In this
    example, we end up modding out the ideal `(x)` from the ring
    `\QQ[x,y]`::

        sage: R.<x,y> = PolynomialRing(QQ,2)
        sage: S.<a,b> = QuotientRing(R,R.ideal(1 + y^2))
        sage: T.<c,d> = QuotientRing(S,S.ideal(a))
        sage: T
        Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x, y^2 + 1)
        sage: R.gens(); S.gens(); T.gens()
        (x, y)
        (a, b)
        (0, d)
        sage: for n in range(4): d^n
        1
        d
        -1
        -d

    TESTS:

    By :trac:`11068`, the following does not return a generic
    quotient ring but a usual quotient of the integer ring::

        sage: R = Integers(8)
        sage: I = R.ideal(2)
        sage: R.quotient(I)
        Ring of integers modulo 2

    Here is an example of the quotient of a free algebra by a
    twosided homogeneous ideal (see :trac:`7797`)::

        sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace')
        sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F
        sage: Q.<a,b,c> = F.quo(I); Q
        Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*y + y*z, x*x + x*y - y*x - y*y)
        sage: a*b
        -b*c
        sage: a^3
        -b*c*a - b*c*b - b*c*c
        sage: J = Q*[a^3-b^3]*Q
        sage: R.<i,j,k> = Q.quo(J); R
        Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (-y*y*z - y*z*x - 2*y*z*z, x*y + y*z, x*x + x*y - y*x - y*y)
        sage: i^3
        -j*k*i - j*k*j - j*k*k
        sage: j^3
        -j*k*i - j*k*j - j*k*k

    Check that :trac:`5978` is fixed by if we quotient by the zero ideal `(0)`
    then we just return ``R``::

        sage: R = QQ['x']
        sage: R.quotient(R.zero_ideal())
        Univariate Polynomial Ring in x over Rational Field
        sage: R.<x> = PolynomialRing(ZZ)
        sage: R is R.quotient(R.zero_ideal())
        True
        sage: I = R.ideal(0)
        sage: R is R.quotient(I)
        True
    """
    # 1. Not all rings inherit from the base class of rings.
    # 2. We want to support quotients of free algebras by homogeneous two-sided ideals.
    #if not isinstance(R, commutative_ring.CommutativeRing):
    #    raise TypeError, "R must be a commutative ring."
    from sage.all import Integers, ZZ
    if not R in Rings():
        raise TypeError("R must be a ring.")
    try:
        is_commutative = R.is_commutative()
    except (AttributeError, NotImplementedError):
        is_commutative = False
    if names is None:
        try:
            names = tuple([x + 'bar' for x in R.variable_names()])
        except ValueError: # no names are assigned
            pass
    else:
        names = normalize_names(R.ngens(), names)
    if not isinstance(I, ideal.Ideal_generic) or I.ring() != R:
        I = R.ideal(I)
    if I.is_zero():
        return R
    try:
        if I.is_principal():
            return R.quotient_by_principal_ideal(I.gen(), names)
    except (AttributeError, NotImplementedError):
        pass
    if not is_commutative:
        try:
            if I.side() != 'twosided':
                raise AttributeError
        except AttributeError:
            raise TypeError("A twosided ideal is required.")
    if isinstance(R, QuotientRing_nc):
        pi = R.cover()
        S = pi.domain()
        G = [pi.lift(x) for x in I.gens()]
        I_lift = S.ideal(G)
        J = R.defining_ideal()
        if S == ZZ:
            return Integers((I_lift+J).gen())
        return R.__class__(S, I_lift + J, names=names)
    if isinstance(R, ring.CommutativeRing):
        return QuotientRing_generic(R, I, names)
    return QuotientRing_nc(R, I, names)
Example #16
0
 def create_key(self, n, names):
     n = int(n)
     names = normalize_names(n, names)
     return (n, names)
Example #17
0
    def create_key_and_extra_args(
        self, order, name=None, modulus=None, names=None, impl=None, proof=None, check_irreducible=True, **kwds
    ):
        """
        EXAMPLES::

            sage: GF.create_key_and_extra_args(9, 'a')
            ((9, ('a',), x^2 + 2*x + 2, 'givaro', '{}', 3, 2, True), {})
            sage: GF.create_key_and_extra_args(9, 'a', foo='value')
            ((9, ('a',), x^2 + 2*x + 2, 'givaro', "{'foo': 'value'}", 3, 2, True), {'foo': 'value'})
        """
        import sage.rings.arith
        from sage.structure.proof.all import WithProof, arithmetic

        if proof is None:
            proof = arithmetic()
        with WithProof("arithmetic", proof):
            order = Integer(order)
            if order <= 1:
                raise ValueError("the order of a finite field must be at least 2")

            if order.is_prime():
                p = order
                n = Integer(1)
                if impl is None:
                    impl = "modn"
                name = ("x",)  # Ignore name
                # Every polynomial of degree 1 is irreducible
                check_irreducible = False
            elif order.is_prime_power():
                if names is not None:
                    name = names
                if name is not None:
                    name = normalize_names(1, name)

                p, n = order.factor()[0]

                # The following is a temporary solution that allows us
                # to construct compatible systems of finite fields
                # until algebraic closures of finite fields are
                # implemented in Sage.  It requires the user to
                # specify two parameters:
                #
                # - `conway` -- boolean; if True, this field is
                #   constructed to fit in a compatible system using
                #   a Conway polynomial.
                # - `prefix` -- a string used to generate names for
                #   automatically constructed finite fields
                #
                # See the docstring of FiniteFieldFactory for examples.
                #
                # Once algebraic closures of finite fields are
                # implemented, this syntax should be superseded by
                # something like the following:
                #
                #     sage: Fpbar = GF(5).algebraic_closure('z')
                #     sage: F, e = Fpbar.subfield(3)  # e is the embedding into Fpbar
                #     sage: F
                #     Finite field in z3 of size 5^3
                #
                # This temporary solution only uses actual Conway
                # polynomials (no pseudo-Conway polynomials), since
                # pseudo-Conway polynomials are not unique, and until
                # we have algebraic closures of finite fields, there
                # is no good place to store a specific choice of
                # pseudo-Conway polynomials.
                if name is None:
                    if not ("conway" in kwds and kwds["conway"]):
                        raise ValueError("parameter 'conway' is required if no name given")
                    if "prefix" not in kwds:
                        raise ValueError("parameter 'prefix' is required if no name given")
                    name = kwds["prefix"] + str(n)

                if "conway" in kwds and kwds["conway"]:
                    from conway_polynomials import conway_polynomial

                    if "prefix" not in kwds:
                        raise ValueError("a prefix must be specified if conway=True")
                    if modulus is not None:
                        raise ValueError("no modulus may be specified if conway=True")
                    # The following raises a RuntimeError if no polynomial is found.
                    modulus = conway_polynomial(p, n)

                if impl is None:
                    if order < zech_log_bound:
                        impl = "givaro"
                    elif p == 2:
                        impl = "ntl"
                    else:
                        impl = "pari_ffelt"
            else:
                raise ValueError("the order of a finite field must be a prime power")

            # Determine modulus.
            # For the 'modn' implementation, we use the following
            # optimization which we also need to avoid an infinite loop:
            # a modulus of None is a shorthand for x-1.
            if modulus is not None or impl != "modn":
                R = PolynomialRing(FiniteField(p), "x")
                if modulus is None:
                    modulus = R.irreducible_element(n)
                if isinstance(modulus, str):
                    # A string specifies an algorithm to find a suitable modulus.
                    if modulus == "default":
                        from sage.misc.superseded import deprecation

                        deprecation(
                            16983,
                            "the modulus 'default' is deprecated, use modulus=None instead (which is the default)",
                        )
                        modulus = None
                    modulus = R.irreducible_element(n, algorithm=modulus)
                else:
                    if sage.rings.polynomial.polynomial_element.is_Polynomial(modulus):
                        modulus = modulus.change_variable_name("x")
                    modulus = R(modulus).monic()

                    if modulus.degree() != n:
                        raise ValueError("the degree of the modulus does not equal the degree of the field")
                    if check_irreducible and not modulus.is_irreducible():
                        raise ValueError("finite field modulus must be irreducible but it is not")
                # If modulus is x - 1 for impl="modn", set it to None
                if impl == "modn" and modulus[0] == -1:
                    modulus = None

            return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
Example #18
0
def QuotientRing(R, I, names=None):
    r"""
    Creates a quotient ring of the ring `R` by the twosided ideal `I`.

    Variables are labeled by ``names`` (if the quotient ring is a quotient
    of a polynomial ring).  If ``names`` isn't given, 'bar' will be appended
    to the variable names in `R`.

    INPUT:

    - ``R`` -- a ring.

    - ``I`` -- a twosided ideal of `R`.

    - ``names`` -- (optional) a list of strings to be used as names for
      the variables in the quotient ring `R/I`.

    OUTPUT: `R/I` - the quotient ring `R` mod the ideal `I`

    ASSUMPTION:

    ``I`` has a method ``I.reduce(x)`` returning the normal form
    of elements `x\in R`. In other words, it is required that
    ``I.reduce(x)==I.reduce(y)`` `\iff x-y \in I`, and
    ``x-I.reduce(x) in I``, for all `x,y\in R`.

    EXAMPLES:

    Some simple quotient rings with the integers::

        sage: R = QuotientRing(ZZ,7*ZZ); R
        Quotient of Integer Ring by the ideal (7)
        sage: R.gens()
        (1,)
        sage: 1*R(3); 6*R(3); 7*R(3)
        3
        4
        0

    ::

        sage: S = QuotientRing(ZZ,ZZ.ideal(8)); S
        Quotient of Integer Ring by the ideal (8)
        sage: 2*S(4)
        0

    With polynomial rings (note that the variable name of the quotient
    ring can be specified as shown below)::

        sage: R.<xx> = QuotientRing(QQ[x], QQ[x].ideal(x^2 + 1)); R
        Univariate Quotient Polynomial Ring in xx over Rational Field with modulus x^2 + 1
        sage: R.gens(); R.gen()
        (xx,)
        xx
        sage: for n in range(4): xx^n
        1
        xx
        -1
        -xx

    ::

        sage: S = QuotientRing(QQ[x], QQ[x].ideal(x^2 - 2)); S
        Univariate Quotient Polynomial Ring in xbar over Rational Field with
        modulus x^2 - 2
        sage: xbar = S.gen(); S.gen()
        xbar
        sage: for n in range(3): xbar^n
        1
        xbar
        2

    Sage coerces objects into ideals when possible::

        sage: R = QuotientRing(QQ[x], x^2 + 1); R
        Univariate Quotient Polynomial Ring in xbar over Rational Field with
        modulus x^2 + 1

    By Noether's homomorphism theorems, the quotient of a quotient ring
    of `R` is just the quotient of `R` by the sum of the ideals. In this
    example, we end up modding out the ideal `(x)` from the ring
    `\QQ[x,y]`::

        sage: R.<x,y> = PolynomialRing(QQ,2)
        sage: S.<a,b> = QuotientRing(R,R.ideal(1 + y^2))
        sage: T.<c,d> = QuotientRing(S,S.ideal(a))
        sage: T
        Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x, y^2 + 1)
        sage: R.gens(); S.gens(); T.gens()
        (x, y)
        (a, b)
        (0, d)
        sage: for n in range(4): d^n
        1
        d
        -1
        -d

    TESTS:

    By :trac:`11068`, the following does not return a generic
    quotient ring but a usual quotient of the integer ring::

        sage: R = Integers(8)
        sage: I = R.ideal(2)
        sage: R.quotient(I)
        Ring of integers modulo 2

    Here is an example of the quotient of a free algebra by a
    twosided homogeneous ideal (see :trac:`7797`)::

        sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace')
        sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F
        sage: Q.<a,b,c> = F.quo(I); Q
        Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*y + y*z, x*x + x*y - y*x - y*y)
        sage: a*b
        -b*c
        sage: a^3
        -b*c*a - b*c*b - b*c*c
        sage: J = Q*[a^3-b^3]*Q
        sage: R.<i,j,k> = Q.quo(J); R
        Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (-y*y*z - y*z*x - 2*y*z*z, x*y + y*z, x*x + x*y - y*x - y*y)
        sage: i^3
        -j*k*i - j*k*j - j*k*k
        sage: j^3
        -j*k*i - j*k*j - j*k*k

    Check that :trac:`5978` is fixed by if we quotient by the zero ideal `(0)`
    then we just return ``R``::

        sage: R = QQ['x']
        sage: R.quotient(R.zero_ideal())
        Univariate Polynomial Ring in x over Rational Field
        sage: R.<x> = PolynomialRing(ZZ)
        sage: R is R.quotient(R.zero_ideal())
        True
        sage: I = R.ideal(0)
        sage: R is R.quotient(I)
        True
    """
    # 1. Not all rings inherit from the base class of rings.
    # 2. We want to support quotients of free algebras by homogeneous two-sided ideals.
    #if not isinstance(R, commutative_ring.CommutativeRing):
    #    raise TypeError, "R must be a commutative ring."
    from sage.all import Integers, ZZ
    if not R in Rings():
        raise TypeError("R must be a ring.")
    try:
        is_commutative = R.is_commutative()
    except (AttributeError, NotImplementedError):
        is_commutative = False
    if names is None:
        try:
            names = tuple([x + 'bar' for x in R.variable_names()])
        except ValueError:  # no names are assigned
            pass
    else:
        names = normalize_names(R.ngens(), names)
    if not isinstance(I, ideal.Ideal_generic) or I.ring() != R:
        I = R.ideal(I)
    if I.is_zero():
        return R
    try:
        if I.is_principal():
            return R.quotient_by_principal_ideal(I.gen(), names)
    except (AttributeError, NotImplementedError):
        pass
    if not is_commutative:
        try:
            if I.side() != 'twosided':
                raise AttributeError
        except AttributeError:
            raise TypeError("A twosided ideal is required.")
    if isinstance(R, QuotientRing_nc):
        pi = R.cover()
        S = pi.domain()
        G = [pi.lift(x) for x in I.gens()]
        I_lift = S.ideal(G)
        J = R.defining_ideal()
        if S == ZZ:
            return Integers((I_lift + J).gen())
        return R.__class__(S, I_lift + J, names=names)
    if isinstance(R, ring.CommutativeRing):
        return QuotientRing_generic(R, I, names)
    return QuotientRing_nc(R, I, names)
Example #19
0
def AffineSpace(n, R=None, names=None, ambient_projective_space=None,
                default_embedding_index=None):
    r"""
    Return affine space of dimension ``n`` over the ring ``R``.

    EXAMPLES:

    The dimension and ring can be given in either order::

        sage: AffineSpace(3, QQ, 'x')
        Affine Space of dimension 3 over Rational Field
        sage: AffineSpace(5, QQ, 'x')
        Affine Space of dimension 5 over Rational Field
        sage: A = AffineSpace(2, QQ, names='XY'); A
        Affine Space of dimension 2 over Rational Field
        sage: A.coordinate_ring()
        Multivariate Polynomial Ring in X, Y over Rational Field

    Use the divide operator for base extension::

        sage: AffineSpace(5, names='x')/GF(17)
        Affine Space of dimension 5 over Finite Field of size 17

    The default base ring is `\ZZ`::

        sage: AffineSpace(5, names='x')
        Affine Space of dimension 5 over Integer Ring

    There is also an affine space associated to each polynomial ring::

        sage: R = GF(7)['x, y, z']
        sage: A = AffineSpace(R); A
        Affine Space of dimension 3 over Finite Field of size 7
        sage: A.coordinate_ring() is R
        True

    TESTS::

            sage: R.<w> = QQ[]
            sage: A.<w> = AffineSpace(R)
            sage: A.gens() == R.gens()
            True

        ::

            sage: R.<x> = QQ[]
            sage: A.<z> = AffineSpace(R)
            Traceback (most recent call last):
            ...
            NameError: variable names passed to AffineSpace conflict with names in ring
    """
    if (is_MPolynomialRing(n) or is_PolynomialRing(n)) and R is None:
        R = n
        if names is not None:
            # Check for the case that the user provided a variable name
            # That does not match what we wanted to use from R
            names = normalize_names(R.ngens(), names)
            if n.variable_names() != names:
                # The provided name doesn't match the name of R's variables
                raise NameError("variable names passed to AffineSpace conflict with names in ring")
        A = AffineSpace(R.ngens(), R.base_ring(), R.variable_names())
        A._coordinate_ring = R
        return A
    if names is None:
        if n == 0:
            names = ''
        else:
            names = 'x'
    if isinstance(R, integer_types + (Integer,)):
        n, R = R, n
    if R is None:
        R = ZZ  # default is the integers
    names = normalize_names(n, names)
    if default_embedding_index is not None and ambient_projective_space is None:
        from sage.schemes.projective.projective_space import ProjectiveSpace
        ambient_projective_space = ProjectiveSpace(n, R)
    if R in _Fields:
        if is_FiniteField(R):
            return AffineSpace_finite_field(n, R, names,
                                            ambient_projective_space, default_embedding_index)
        else:
            return AffineSpace_field(n, R, names,
                                     ambient_projective_space, default_embedding_index)
    return AffineSpace_generic(n, R, names, ambient_projective_space, default_embedding_index)
Example #20
0
    def create_key_and_extra_args(
        self, order, name=None, modulus=None, names=None, impl=None, proof=None, check_irreducible=True, **kwds
    ):
        """
        EXAMPLES::

            sage: GF.create_key_and_extra_args(9, 'a')
            ((9, ('a',), x^2 + 2*x + 2, 'givaro', '{}', 3, 2, True), {})
            sage: GF.create_key_and_extra_args(9, 'a', foo='value')
            ((9, ('a',), x^2 + 2*x + 2, 'givaro', "{'foo': 'value'}", 3, 2, True), {'foo': 'value'})
        """
        import sage.arith.all
        from sage.structure.proof.all import WithProof, arithmetic

        if proof is None:
            proof = arithmetic()
        with WithProof("arithmetic", proof):
            order = Integer(order)
            if order <= 1:
                raise ValueError("the order of a finite field must be at least 2")

            if order.is_prime():
                p = order
                n = Integer(1)
                if impl is None:
                    impl = "modn"
                name = ("x",)  # Ignore name
                # Every polynomial of degree 1 is irreducible
                check_irreducible = False
            elif order.is_prime_power():
                if names is not None:
                    name = names
                if name is not None:
                    name = normalize_names(1, name)

                p, n = order.factor()[0]
                if name is None:
                    if "prefix" not in kwds:
                        kwds["prefix"] = "z"
                    name = kwds["prefix"] + str(n)
                    if modulus is not None:
                        raise ValueError("no modulus may be specified if variable name not given")
                    if "conway" in kwds:
                        del kwds["conway"]
                        from sage.misc.superseded import deprecation

                        deprecation(
                            17569,
                            "the 'conway' argument is deprecated, pseudo-conway polynomials are now used by default if no variable name is given",
                        )
                    # Fpbar will have a strong reference, since algebraic_closure caches its results,
                    # and the coefficients of modulus lie in GF(p)
                    Fpbar = GF(p).algebraic_closure(kwds.get("prefix", "z"))
                    # This will give a Conway polynomial if p,n is small enough to be in the database
                    # and a pseudo-Conway polynomial if it's not.
                    modulus = Fpbar._get_polynomial(n)
                    check_irreducible = False

                if impl is None:
                    if order < zech_log_bound:
                        impl = "givaro"
                    elif p == 2:
                        impl = "ntl"
                    else:
                        impl = "pari_ffelt"
            else:
                raise ValueError("the order of a finite field must be a prime power")

            # Determine modulus.
            # For the 'modn' implementation, we use the following
            # optimization which we also need to avoid an infinite loop:
            # a modulus of None is a shorthand for x-1.
            if modulus is not None or impl != "modn":
                R = PolynomialRing(FiniteField(p), "x")
                if modulus is None:
                    modulus = R.irreducible_element(n)
                if isinstance(modulus, str):
                    # A string specifies an algorithm to find a suitable modulus.
                    if modulus == "default":
                        from sage.misc.superseded import deprecation

                        deprecation(
                            16983,
                            "the modulus 'default' is deprecated, use modulus=None instead (which is the default)",
                        )
                        modulus = None
                    modulus = R.irreducible_element(n, algorithm=modulus)
                else:
                    if sage.rings.polynomial.polynomial_element.is_Polynomial(modulus):
                        modulus = modulus.change_variable_name("x")
                    modulus = R(modulus).monic()

                    if modulus.degree() != n:
                        raise ValueError("the degree of the modulus does not equal the degree of the field")
                    if check_irreducible and not modulus.is_irreducible():
                        raise ValueError("finite field modulus must be irreducible but it is not")
                # If modulus is x - 1 for impl="modn", set it to None
                if impl == "modn" and modulus[0] == -1:
                    modulus = None

            return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
    def create_key_and_extra_args(self,
                                  order,
                                  name=None,
                                  modulus=None,
                                  names=None,
                                  impl=None,
                                  proof=None,
                                  check_irreducible=True,
                                  **kwds):
        """
        EXAMPLES::

            sage: GF.create_key_and_extra_args(9, 'a')
            ((9, ('a',), x^2 + 2*x + 2, 'givaro', '{}', 3, 2, True), {})
            sage: GF.create_key_and_extra_args(9, 'a', foo='value')
            ((9, ('a',), x^2 + 2*x + 2, 'givaro', "{'foo': 'value'}", 3, 2, True), {'foo': 'value'})
        """
        import sage.arith.all
        from sage.structure.proof.all import WithProof, arithmetic
        if proof is None:
            proof = arithmetic()
        with WithProof('arithmetic', proof):
            order = Integer(order)
            if order <= 1:
                raise ValueError(
                    "the order of a finite field must be at least 2")

            if order.is_prime():
                p = order
                n = Integer(1)
                if impl is None:
                    impl = 'modn'
                name = ('x', )  # Ignore name
                # Every polynomial of degree 1 is irreducible
                check_irreducible = False
            elif order.is_prime_power():
                if names is not None:
                    name = names
                if name is not None:
                    name = normalize_names(1, name)

                p, n = order.factor()[0]
                if name is None:
                    if 'prefix' not in kwds:
                        kwds['prefix'] = 'z'
                    name = kwds['prefix'] + str(n)
                    if modulus is not None:
                        raise ValueError(
                            "no modulus may be specified if variable name not given"
                        )
                    if 'conway' in kwds:
                        del kwds['conway']
                        from sage.misc.superseded import deprecation
                        deprecation(
                            17569,
                            "the 'conway' argument is deprecated, pseudo-conway polynomials are now used by default if no variable name is given"
                        )
                    # Fpbar will have a strong reference, since algebraic_closure caches its results,
                    # and the coefficients of modulus lie in GF(p)
                    Fpbar = GF(p).algebraic_closure(kwds.get('prefix', 'z'))
                    # This will give a Conway polynomial if p,n is small enough to be in the database
                    # and a pseudo-Conway polynomial if it's not.
                    modulus = Fpbar._get_polynomial(n)
                    check_irreducible = False

                if impl is None:
                    if order < zech_log_bound:
                        impl = 'givaro'
                    elif p == 2:
                        impl = 'ntl'
                    else:
                        impl = 'pari_ffelt'
            else:
                raise ValueError(
                    "the order of a finite field must be a prime power")

            # Determine modulus.
            # For the 'modn' implementation, we use the following
            # optimization which we also need to avoid an infinite loop:
            # a modulus of None is a shorthand for x-1.
            if modulus is not None or impl != 'modn':
                R = PolynomialRing(FiniteField(p), 'x')
                if modulus is None:
                    modulus = R.irreducible_element(n)
                if isinstance(modulus, str):
                    # A string specifies an algorithm to find a suitable modulus.
                    if modulus == "default":
                        from sage.misc.superseded import deprecation
                        deprecation(
                            16983,
                            "the modulus 'default' is deprecated, use modulus=None instead (which is the default)"
                        )
                        modulus = None
                    modulus = R.irreducible_element(n, algorithm=modulus)
                else:
                    if sage.rings.polynomial.polynomial_element.is_Polynomial(
                            modulus):
                        modulus = modulus.change_variable_name('x')
                    modulus = R(modulus).monic()

                    if modulus.degree() != n:
                        raise ValueError(
                            "the degree of the modulus does not equal the degree of the field"
                        )
                    if check_irreducible and not modulus.is_irreducible():
                        raise ValueError(
                            "finite field modulus must be irreducible but it is not"
                        )
                # If modulus is x - 1 for impl="modn", set it to None
                if impl == 'modn' and modulus[0] == -1:
                    modulus = None

            return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
def SkewPolynomialRing(base_ring,
                       base_ring_automorphism=None,
                       names=None,
                       sparse=False):
    r"""
    Return the globally unique skew polynomial ring with the given properties
    and variable names.

    Given a ring `R` and a ring automorphism `\sigma` of `R`, the ring of
    skew polynomials `R[X, \sigma]` is the usual abelian group polynomial
    `R[X]` equipped with the modification multiplication deduced from the
    rule `X a = \sigma(a) X`.

    .. SEEALSO::

        - :class:`sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_general`
        - :class:`sage.rings.polynomial.skew_polynomial_element.SkewPolynomial`

    INPUT:

    - ``base_ring`` -- a commutative ring

    - ``base_ring_automorphism`` -- an automorphism of the base ring
      (also called twisting map)

    - ``names`` -- a string or a list of strings

    - ``sparse`` -- a boolean (default: ``False``). Currently not supported.

    .. NOTE::

        The current implementation of skew polynomial rings does not
        support derivations. Sparse skew polynomials and multivariate skew
        polynomials are also not implemented.

    OUTPUT:

    A univariate skew polynomial ring over ``base_ring`` twisted by
    ``base_ring_automorphism`` when ``names`` is a string with no
    commas (``,``) or a list of length 1. Otherwise we raise a
    ``NotImplementedError`` as multivariate skew polynomial rings are
    not yet implemented.

    UNIQUENESS and IMMUTABILITY:

    In Sage, there is exactly one skew polynomial ring for each
    triple (base ring, twisting map, name of the variable).

        EXAMPLES of VARIABLE NAME CONTEXT::

            sage: R.<t> = ZZ[]
            sage: sigma = R.hom([t+1])
            sage: S.<x> = SkewPolynomialRing(R, sigma); S
            Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring
             twisted by t |--> t + 1

        The names of the variables defined above cannot be arbitrarily
        modified because each skew polynomial ring is unique in Sage and other
        objects in Sage could have pointers to that skew polynomial ring.

        However, the variable can be changed within the scope of a ``with``
        block using the localvars context::

            sage: with localvars(S, ['y']):
            ....:     print(S)
            Skew Polynomial Ring in y over Univariate Polynomial Ring in t over Integer Ring
             twisted by t |--> t + 1

    SQUARE BRACKETS NOTATION:

    You can alternatively create a skew polynomial ring over `R`
    twisted by ``base_ring_automorphism`` by writing
    ``R['varname', base_ring_automorphism]``.

    EXAMPLES:

    We first define the base ring::

        sage: R.<t> = ZZ[]; R
        Univariate Polynomial Ring in t over Integer Ring

    and the twisting map::

        sage: base_ring_automorphism = R.hom([t+1]); base_ring_automorphism
        Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring
          Defn: t |--> t + 1

    Now, we are ready to define the skew polynomial ring::

        sage: S = SkewPolynomialRing(R, base_ring_automorphism, names='x'); S
        Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring
         twisted by t |--> t + 1

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

        sage: S.<x> = SkewPolynomialRing(R, base_ring_automorphism)
        sage: (x + t)^2
        x^2 + (2*t + 1)*x + t^2

    Here is an example with the square bracket notations::

        sage: S.<x> = R['x', base_ring_automorphism]; S
        Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring
         twisted by t |--> t + 1

    Rings with different variables names are different::

        sage: R['x', base_ring_automorphism] == R['y', base_ring_automorphism]
        False

    TESTS:

    You must specify a variable name::

        sage: SkewPolynomialRing(R, base_ring_automorphism)
        Traceback (most recent call last):
        ...
        TypeError: you must specify the name of the variable

    With this syntax, it is not possible to omit the name of the
    variable neither in LHS nor in RHS. If we omit it in LHS, the
    variable is not created::

        sage: Sy = R['y', base_ring_automorphism]; Sy
        Skew Polynomial Ring in y over Univariate Polynomial Ring in t over Integer Ring
         twisted by t |--> t + 1
        sage: y.parent()
        Traceback (most recent call last):
        ...
        NameError: name 'y' is not defined

    If we omit it in RHS, sage tries to create a polynomial ring and fails::

        sage: Sz.<z> = R[base_ring_automorphism]
        Traceback (most recent call last):
        ...
        ValueError: variable name 'Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring\n  Defn: t |--> t + 1' is not alphanumeric

    Multivariate skew polynomial rings are not supported::

        sage: S = SkewPolynomialRing(R, base_ring_automorphism,names=['x','y'])
        Traceback (most recent call last):
        ...
        NotImplementedError: multivariate skew polynomials rings not supported

    Sparse skew polynomial rings are not implemented::

        sage: S = SkewPolynomialRing(R, base_ring_automorphism, names='x', sparse=True)
        Traceback (most recent call last):
        ...
        NotImplementedError: sparse skew polynomial rings are not implemented

    .. TODO::

        - Sparse Skew Polynomial Ring
        - Multivariate Skew Polynomial Ring
        - Add derivations.
    """
    if base_ring not in categories.rings.Rings().Commutative():
        raise TypeError("base_ring must be a commutative ring")
    if base_ring_automorphism is None:
        base_ring_automorphism = IdentityMorphism(base_ring)
    else:
        if (not isinstance(base_ring_automorphism, Morphism)
                or base_ring_automorphism.domain() != base_ring
                or base_ring_automorphism.codomain() != base_ring):
            raise TypeError(
                "base_ring_automorphism must be a ring automorphism of base_ring (=%s)"
                % base_ring)
    if sparse:
        raise NotImplementedError(
            "sparse skew polynomial rings are not implemented")
    if names is None:
        raise TypeError("you must specify the name of the variable")
    try:
        names = normalize_names(1, names)[0]
    except IndexError:
        raise NotImplementedError(
            "multivariate skew polynomials rings not supported")

    from sage.rings.polynomial.skew_polynomial_ring import SkewPolynomialRing_general
    return SkewPolynomialRing_general(base_ring, base_ring_automorphism, names,
                                      sparse)
Example #23
0
    def create_key(self, base_ring, arg1=None, arg2=None,
            sparse=None, order='degrevlex',
            names=None, name=None,
            implementation=None, degrees=None):
        """
        Create the key under which a free algebra is stored.

        TESTS::

            sage: FreeAlgebra.create_key(GF(5),['x','y','z'])
            (Finite Field of size 5, ('x', 'y', 'z'))
            sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3)
            (Finite Field of size 5, ('x', 'y', 'z'))
            sage: FreeAlgebra.create_key(GF(5),3,'xyz')
            (Finite Field of size 5, ('x', 'y', 'z'))
            sage: FreeAlgebra.create_key(GF(5),['x','y','z'], implementation='letterplace')
            (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
            sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3, implementation='letterplace')
            (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
            sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace')
            (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
            sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace', degrees=[1,2,3])
            ((1, 2, 3), Multivariate Polynomial Ring in x, y, z, x_ over Finite Field of size 5)

        """
        if arg1 is None and arg2 is None and names is None:
            # this is used for pickling
            if degrees is None:
                return (base_ring,)
            return tuple(degrees),base_ring
        # test if we can use libSingular/letterplace
        if implementation == "letterplace":
            args = [arg for arg in (arg1, arg2) if arg is not None]
            kwds = dict(sparse=sparse, order=order, implementation="singular")
            if name is not None:
                kwds["name"] = name
            if names is not None:
                kwds["names"] = names
            PolRing = PolynomialRing(base_ring, *args, **kwds)
            if degrees is None:
                return (PolRing,)
            from sage.all import TermOrder
            T = PolRing.term_order() + TermOrder('lex',1)
            varnames = list(PolRing.variable_names())
            newname = 'x'
            while newname in varnames:
                newname += '_'
            varnames.append(newname)
            R = PolynomialRing(
                    PolRing.base(), varnames,
                    sparse=sparse, order=T)
            return tuple(degrees), R
        # normalise the generator names
        from sage.all import Integer
        if isinstance(arg1, (Integer,) + integer_types):
            arg1, arg2 = arg2, arg1
        if not names is None:
            arg1 = names
        elif not name is None:
            arg1 = name
        if arg2 is None:
            arg2 = len(arg1)
        names = normalize_names(arg2, arg1)
        return base_ring, names
Example #24
0
    def create_key_and_extra_args(self,
                                  order,
                                  name=None,
                                  modulus=None,
                                  names=None,
                                  impl=None,
                                  proof=None,
                                  check_irreducible=True,
                                  **kwds):
        """
        EXAMPLES::

            sage: GF.create_key_and_extra_args(9, 'a')
            ((9, ('a',), x^2 + 2*x + 2, 'givaro', '{}', 3, 2, True), {})
            sage: GF.create_key_and_extra_args(9, 'a', foo='value')
            ((9, ('a',), x^2 + 2*x + 2, 'givaro', "{'foo': 'value'}", 3, 2, True), {'foo': 'value'})
        """
        import sage.arith.all
        from sage.structure.proof.all import WithProof, arithmetic
        if proof is None:
            proof = arithmetic()
        with WithProof('arithmetic', proof):
            order = Integer(order)
            if order <= 1:
                raise ValueError(
                    "the order of a finite field must be at least 2")

            if order.is_prime():
                p = order
                n = Integer(1)
                if impl is None:
                    impl = 'modn'
                name = ('x', )  # Ignore name
                # Every polynomial of degree 1 is irreducible
                check_irreducible = False
            elif order.is_prime_power():
                if names is not None:
                    name = names
                if name is not None:
                    name = normalize_names(1, name)

                p, n = order.factor()[0]

                # The following is a temporary solution that allows us
                # to construct compatible systems of finite fields
                # until algebraic closures of finite fields are
                # implemented in Sage.  It requires the user to
                # specify two parameters:
                #
                # - `conway` -- boolean; if True, this field is
                #   constructed to fit in a compatible system using
                #   a Conway polynomial.
                # - `prefix` -- a string used to generate names for
                #   automatically constructed finite fields
                #
                # See the docstring of FiniteFieldFactory for examples.
                #
                # Once algebraic closures of finite fields are
                # implemented, this syntax should be superseded by
                # something like the following:
                #
                #     sage: Fpbar = GF(5).algebraic_closure('z')
                #     sage: F, e = Fpbar.subfield(3)  # e is the embedding into Fpbar
                #     sage: F
                #     Finite field in z3 of size 5^3
                #
                # This temporary solution only uses actual Conway
                # polynomials (no pseudo-Conway polynomials), since
                # pseudo-Conway polynomials are not unique, and until
                # we have algebraic closures of finite fields, there
                # is no good place to store a specific choice of
                # pseudo-Conway polynomials.
                if name is None:
                    if not ('conway' in kwds and kwds['conway']):
                        raise ValueError(
                            "parameter 'conway' is required if no name given")
                    if 'prefix' not in kwds:
                        raise ValueError(
                            "parameter 'prefix' is required if no name given")
                    name = kwds['prefix'] + str(n)

                if 'conway' in kwds and kwds['conway']:
                    from conway_polynomials import conway_polynomial
                    if 'prefix' not in kwds:
                        raise ValueError(
                            "a prefix must be specified if conway=True")
                    if modulus is not None:
                        raise ValueError(
                            "no modulus may be specified if conway=True")
                    # The following raises a RuntimeError if no polynomial is found.
                    modulus = conway_polynomial(p, n)

                if impl is None:
                    if order < zech_log_bound:
                        impl = 'givaro'
                    elif p == 2:
                        impl = 'ntl'
                    else:
                        impl = 'pari_ffelt'
            else:
                raise ValueError(
                    "the order of a finite field must be a prime power")

            # Determine modulus.
            # For the 'modn' implementation, we use the following
            # optimization which we also need to avoid an infinite loop:
            # a modulus of None is a shorthand for x-1.
            if modulus is not None or impl != 'modn':
                R = PolynomialRing(FiniteField(p), 'x')
                if modulus is None:
                    modulus = R.irreducible_element(n)
                if isinstance(modulus, str):
                    # A string specifies an algorithm to find a suitable modulus.
                    if modulus == "default":
                        from sage.misc.superseded import deprecation
                        deprecation(
                            16983,
                            "the modulus 'default' is deprecated, use modulus=None instead (which is the default)"
                        )
                        modulus = None
                    modulus = R.irreducible_element(n, algorithm=modulus)
                else:
                    if sage.rings.polynomial.polynomial_element.is_Polynomial(
                            modulus):
                        modulus = modulus.change_variable_name('x')
                    modulus = R(modulus).monic()

                    if modulus.degree() != n:
                        raise ValueError(
                            "the degree of the modulus does not equal the degree of the field"
                        )
                    if check_irreducible and not modulus.is_irreducible():
                        raise ValueError(
                            "finite field modulus must be irreducible but it is not"
                        )
                # If modulus is x - 1 for impl="modn", set it to None
                if impl == 'modn' and modulus[0] == -1:
                    modulus = None

            return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
    def create_key_and_extra_args(self, order, name=None, modulus=None, names=None,
                                  impl=None, proof=None, check_irreducible=True,
                                  prefix=None, repr=None, elem_cache=None,
                                  structure=None):
        """
        EXAMPLES::

            sage: GF.create_key_and_extra_args(9, 'a')
            ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True), {})

        We do not take invalid keyword arguments and raise a value error
        to better ensure uniqueness::

            sage: GF.create_key_and_extra_args(9, 'a', foo='value')
            Traceback (most recent call last):
            ...
            TypeError: create_key_and_extra_args() got an unexpected keyword argument 'foo'

        Moreover, ``repr`` and ``elem_cache`` are ignored when not
        using givaro::

            sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', repr='poly')
            ((16, ('a',), x^4 + x + 1, 'ntl', 2, 4, True, None, None, None), {})
            sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', elem_cache=False)
            ((16, ('a',), x^4 + x + 1, 'ntl', 2, 4, True, None, None, None), {})
            sage: GF(16, impl='ntl') is GF(16, impl='ntl', repr='foo')
            True

        We handle extra arguments for the givaro finite field and
        create unique objects for their defaults::

            sage: GF(25, impl='givaro') is GF(25, impl='givaro', repr='poly')
            True
            sage: GF(25, impl='givaro') is GF(25, impl='givaro', elem_cache=True)
            True
            sage: GF(625, impl='givaro') is GF(625, impl='givaro', elem_cache=False)
            True

        We explicitly take a ``structure`` attribute for compatibility
        with :class:`~sage.categories.pushout.AlgebraicExtensionFunctor`
        but we ignore it as it is not used, see :trac:`21433`::

            sage: GF.create_key_and_extra_args(9, 'a', structure=None)
            ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True), {})
        """
        import sage.arith.all
        from sage.structure.proof.all import WithProof, arithmetic
        if proof is None:
            proof = arithmetic()
        with WithProof('arithmetic', proof):
            order = Integer(order)
            if order <= 1:
                raise ValueError("the order of a finite field must be at least 2")

            if order.is_prime():
                p = order
                n = Integer(1)
                if impl is None:
                    impl = 'modn'
                name = ('x',)  # Ignore name
                # Every polynomial of degree 1 is irreducible
                check_irreducible = False
            elif order.is_prime_power():
                if names is not None:
                    name = names
                if name is not None:
                    name = normalize_names(1, name)

                p, n = order.factor()[0]
                if name is None:
                    if prefix is None:
                        prefix = 'z'
                    name = prefix + str(n)
                    if modulus is not None:
                        raise ValueError("no modulus may be specified if variable name not given")
                    # Fpbar will have a strong reference, since algebraic_closure caches its results,
                    # and the coefficients of modulus lie in GF(p)
                    Fpbar = GF(p).algebraic_closure(prefix)
                    # This will give a Conway polynomial if p,n is small enough to be in the database
                    # and a pseudo-Conway polynomial if it's not.
                    modulus = Fpbar._get_polynomial(n)
                    check_irreducible = False

                if impl is None:
                    if order < zech_log_bound:
                        impl = 'givaro'
                    elif p == 2:
                        impl = 'ntl'
                    else:
                        impl = 'pari_ffelt'
            else:
                raise ValueError("the order of a finite field must be a prime power")

            # Determine modulus.
            # For the 'modn' implementation, we use the following
            # optimization which we also need to avoid an infinite loop:
            # a modulus of None is a shorthand for x-1.
            if modulus is not None or impl != 'modn':
                R = PolynomialRing(FiniteField(p), 'x')
                if modulus is None:
                    modulus = R.irreducible_element(n)
                if isinstance(modulus, str):
                    # A string specifies an algorithm to find a suitable modulus.
                    if modulus == "default":
                        from sage.misc.superseded import deprecation
                        deprecation(16983, "the modulus 'default' is deprecated, use modulus=None instead (which is the default)")
                        modulus = None
                    modulus = R.irreducible_element(n, algorithm=modulus)
                else:
                    if sage.rings.polynomial.polynomial_element.is_Polynomial(modulus):
                        modulus = modulus.change_variable_name('x')
                    modulus = R(modulus).monic()

                    if modulus.degree() != n:
                        raise ValueError("the degree of the modulus does not equal the degree of the field")
                    if check_irreducible and not modulus.is_irreducible():
                        raise ValueError("finite field modulus must be irreducible but it is not")
                # If modulus is x - 1 for impl="modn", set it to None
                if impl == 'modn' and modulus[0] == -1:
                    modulus = None

            # Check extra arguments for givaro and setup their defaults
            # TODO: ntl takes a repr, but ignores it
            if impl == 'givaro':
                if repr is None:
                    repr = 'poly'
                if elem_cache is None:
                    elem_cache = (order < 500)
            else:
                # This has the effect of ignoring these keywords
                repr = None
                elem_cache = None

            return (order, name, modulus, impl, p, n, proof, prefix, repr, elem_cache), {}
Example #26
0
def ProductProjectiveSpaces(n, R=None, names='x'):
    r"""
    Returns the Cartesian product of projective spaces. Can input either a list of projective spaces
    over the same base ring or the list of dimensions, the base ring, and the variable names.

    INPUT:

    - ``n`` -- a list of integers or a list of projective spaces

    - ``R`` -- a ring

    - ``names`` -- a string or list of strings

    EXAMPLES::

        sage: P1 = ProjectiveSpace(QQ,2,'x')
        sage: P2 = ProjectiveSpace(QQ,3,'y')
        sage: ProductProjectiveSpaces([P1,P2])
        Product of projective spaces P^2 x P^3 over Rational Field

    ::

        sage: ProductProjectiveSpaces([2,2],GF(7),'y')
        Product of projective spaces P^2 x P^2 over Finite Field of size 7

    ::

        sage: P1 = ProjectiveSpace(ZZ,2,'x')
        sage: P2 = ProjectiveSpace(QQ,3,'y')
        sage: ProductProjectiveSpaces([P1,P2])
        Traceback (most recent call last):
        ...
        AttributeError: Components must be over the same base ring
    """
    if isinstance(R, (list, tuple)):
        n, R = R, n
    if not isinstance(n, (tuple, list)):
        raise TypeError("Must be a list of dimensions")
    if R is None:
        R = QQ  # default is the rationals
    if isinstance(n[0], ProjectiveSpace_ring):
        #this should be a list of projective spaces
        names = []
        N = []
        R = None
        for PS in n:
            if not isinstance(PS,ProjectiveSpace_ring):
                raise TypeError("Must be a list of Projective Spaces or (dimensions,base ring,names)")
            if R is None:
                R = PS.base_ring()
            elif R != PS.base_ring():
                raise AttributeError("Components must be over the same base ring")
            N.append(PS.dimension_relative())
            names += PS.variable_names()
        X = ProductProjectiveSpaces_ring(N, R, names)
        X._components = n
    else:
        if isinstance(R, (list,tuple)):
           n, R = R, n
        if not isinstance(n,(list,tuple)):
            raise ValueError("Need list or tuple of dimensions")
        if not is_CommutativeRing(R):
            raise ValueError("Must be a commutative ring")
        from sage.structure.category_object import normalize_names
        n_vars=sum(d+1 for d in n)
        if isinstance(names, six.string_types):
            names = normalize_names(n_vars, names)
        else:
            name_list = list(names)
            if len(name_list) == len(n):
                names = []
                for name, dim in zip(name_list, n):
                    names += normalize_names(dim+1, name)
            else:
                n_vars = sum(1+d for d in n)
                names = normalize_names(n_vars, name_list)
        X = ProductProjectiveSpaces_ring(n, R, names)
    return(X)
def SkewPolynomialRing(base_ring, base_ring_automorphism=None, names=None, sparse=False):
    r"""
    Return the globally unique skew polynomial ring with the given properties
    and variable names.

    Given a ring `R` and a ring automorphism `\sigma` of `R`, the ring of
    skew polynomials `R[X, \sigma]` is the usual abelian group polynomial
    `R[X]` equipped with the modification multiplication deduced from the
    rule `X a = \sigma(a) X`.

    .. SEEALSO::

        - :class:`sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_general`
        - :class:`sage.rings.polynomial.skew_polynomial_element.SkewPolynomial`

    INPUT:

    - ``base_ring`` -- a commutative ring

    - ``base_ring_automorphism`` -- an automorphism of the base ring
      (also called twisting map)

    - ``names`` -- a string or a list of strings

    - ``sparse`` -- a boolean (default: ``False``). Currently not supported.

    .. NOTE::

        The current implementation of skew polynomial rings does not
        support derivations. Sparse skew polynomials and multivariate skew
        polynomials are also not implemented.

    OUTPUT:

    A univariate skew polynomial ring over ``base_ring`` twisted by
    ``base_ring_automorphism`` when ``names`` is a string with no
    commas (``,``) or a list of length 1. Otherwise we raise a
    ``NotImplementedError`` as multivariate skew polynomial rings are
    not yet implemented.

    UNIQUENESS and IMMUTABILITY:

    In Sage, there is exactly one skew polynomial ring for each
    triple (base ring, twisting map, name of the variable).

        EXAMPLES of VARIABLE NAME CONTEXT::

            sage: R.<t> = ZZ[]
            sage: sigma = R.hom([t+1])
            sage: S.<x> = SkewPolynomialRing(R, sigma); S
            Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring
             twisted by t |--> t + 1

        The names of the variables defined above cannot be arbitrarily
        modified because each skew polynomial ring is unique in Sage and other
        objects in Sage could have pointers to that skew polynomial ring.

        However, the variable can be changed within the scope of a ``with``
        block using the localvars context::

            sage: with localvars(S, ['y']):
            ....:     print(S)
            Skew Polynomial Ring in y over Univariate Polynomial Ring in t over Integer Ring
             twisted by t |--> t + 1

    SQUARE BRACKETS NOTATION:

    You can alternatively create a skew polynomial ring over `R`
    twisted by ``base_ring_automorphism`` by writing
    ``R['varname', base_ring_automorphism]``.

    EXAMPLES:

    We first define the base ring::

        sage: R.<t> = ZZ[]; R
        Univariate Polynomial Ring in t over Integer Ring

    and the twisting map::

        sage: base_ring_automorphism = R.hom([t+1]); base_ring_automorphism
        Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring
          Defn: t |--> t + 1

    Now, we are ready to define the skew polynomial ring::

        sage: S = SkewPolynomialRing(R, base_ring_automorphism, names='x'); S
        Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring
         twisted by t |--> t + 1

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

        sage: S.<x> = SkewPolynomialRing(R, base_ring_automorphism)
        sage: (x + t)^2
        x^2 + (2*t + 1)*x + t^2

    Here is an example with the square bracket notations::

        sage: S.<x> = R['x', base_ring_automorphism]; S
        Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring
         twisted by t |--> t + 1

    Rings with different variables names are different::

        sage: R['x', base_ring_automorphism] == R['y', base_ring_automorphism]
        False

    TESTS:

    You must specify a variable name::

        sage: SkewPolynomialRing(R, base_ring_automorphism)
        Traceback (most recent call last):
        ...
        TypeError: you must specify the name of the variable

    With this syntax, it is not possible to omit the name of the
    variable neither in LHS nor in RHS. If we omit it in LHS, the
    variable is not created::

        sage: Sy = R['y', base_ring_automorphism]; Sy
        Skew Polynomial Ring in y over Univariate Polynomial Ring in t over Integer Ring
         twisted by t |--> t + 1
        sage: y.parent()
        Traceback (most recent call last):
        ...
        NameError: name 'y' is not defined

    If we omit it in RHS, sage tries to create a polynomial ring and fails::

        sage: Sz.<z> = R[base_ring_automorphism]
        Traceback (most recent call last):
        ...
        ValueError: variable name 'Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring\n  Defn: t |--> t + 1' is not alphanumeric

    Multivariate skew polynomial rings are not supported::

        sage: S = SkewPolynomialRing(R, base_ring_automorphism,names=['x','y'])
        Traceback (most recent call last):
        ...
        NotImplementedError: multivariate skew polynomials rings not supported

    Sparse skew polynomial rings are not implemented::

        sage: S = SkewPolynomialRing(R, base_ring_automorphism, names='x', sparse=True)
        Traceback (most recent call last):
        ...
        NotImplementedError: sparse skew polynomial rings are not implemented

    .. TODO::

        - Sparse Skew Polynomial Ring
        - Multivariate Skew Polynomial Ring
        - Add derivations.
    """
    if base_ring not in categories.rings.Rings().Commutative():
        raise TypeError("base_ring must be a commutative ring")
    if base_ring_automorphism is None:
        base_ring_automorphism = IdentityMorphism(base_ring)
    else:
        if (not isinstance(base_ring_automorphism,Morphism)
                or base_ring_automorphism.domain() != base_ring
                or base_ring_automorphism.codomain() != base_ring):
            raise TypeError("base_ring_automorphism must be a ring automorphism of base_ring (=%s)" % base_ring)
    if sparse:
        raise NotImplementedError("sparse skew polynomial rings are not implemented")
    if names is None:
        raise TypeError("you must specify the name of the variable")
    try:
        names = normalize_names(1, names)[0]
    except IndexError:
        raise NotImplementedError("multivariate skew polynomials rings not supported")

    from sage.rings.polynomial.skew_polynomial_ring import SkewPolynomialRing_general
    return SkewPolynomialRing_general(base_ring, base_ring_automorphism, names, sparse)
Example #28
0
def FreeMonoid(index_set=None, names=None, commutative=False, **kwds):
    r"""
    Return a free monoid on `n` generators or with the generators indexed by
    a set `I`.

    We construct free monoids by specifing either:

    - the number of generators and/or the names of the generators
    - the indexing set for the generators

    INPUT:

    - ``index_set`` -- an indexing set for the generators; if an integer,
      than this becomes `\{0, 1, \ldots, n-1\}`

    -  ``names`` -- names of generators

    - ``commutative`` -- (default: ``False``) whether the free monoid is
      commutative or not

    OUTPUT:

    A free monoid.

    EXAMPLES::

        sage: F.<a,b,c,d,e> = FreeMonoid(); F
        Free monoid on 5 generators (a, b, c, d, e)
        sage: FreeMonoid(index_set=ZZ)
        Free monoid indexed by Integer Ring

        sage: F.<x,y,z> = FreeMonoid(abelian=True); F
        Free abelian monoid on 3 generators (x, y, z)
        sage: FreeMonoid(index_set=ZZ, commutative=True)
        Free abelian monoid indexed by Integer Ring

    TESTS::

        sage: FreeMonoid(index_set=ZZ, names='x,y,z')
        Free monoid indexed by Integer Ring
    """
    if 'abelian' in kwds:
        commutative = kwds.pop('abelian')

    if commutative:
        from sage.monoids.free_abelian_monoid import FreeAbelianMonoid
        return FreeAbelianMonoid(index_set, names, **kwds)

    if isinstance(index_set, str): # Swap args (this works if names is None as well)
        names, index_set = index_set, names

    if index_set is None and names is not None:
        if isinstance(names, str):
            index_set = names.count(',')
        else:
            index_set = len(names)

    if index_set not in ZZ:
        if names is not None:
            names = normalize_names(-1, names)
        from sage.monoids.indexed_free_monoid import IndexedFreeMonoid
        return IndexedFreeMonoid(index_set, names=names, **kwds)

    if names is None:
        raise ValueError("names must be specified")
    return FreeMonoid_factory(index_set, names)
Example #29
0
    def center(self, name=None, names=None, default=False):
        r"""
        Return the center of this Ore function field.

        .. NOTE::

            One can prove that the center is a field of rational functions
            over a subfield of the base ring of this Ore function field.

        INPUT:

        - ``name`` -- a string or ``None`` (default: ``None``);
          the name for the central variable

        - ``default`` -- a boolean (default: ``False``); if ``True``,
          set the default variable name for the center to ``name``

        EXAMPLES::

            sage: k.<t> = GF(5^3)
            sage: Frob = k.frobenius_endomorphism()
            sage: S.<x> = k['x',Frob]
            sage: K = S.fraction_field()

            sage: Z = K.center(); Z
            Fraction Field of Univariate Polynomial Ring in z over Finite Field of size 5

        We can pass in another variable name::

            sage: K.center(name='y')
            Fraction Field of Univariate Polynomial Ring in y over Finite Field of size 5

        or use the bracket notation::

            sage: Zy.<y> = K.center(); Zy
            Fraction Field of Univariate Polynomial Ring in y over Finite Field of size 5

        A coercion map from the center to the Ore function field is set::

            sage: K.has_coerce_map_from(Zy)
            True

        and pushout works::

            sage: x.parent()
            Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5
            sage: y.parent()
            Fraction Field of Univariate Polynomial Ring in y over Finite Field of size 5
            sage: P = x + y; P
            x^3 + x
            sage: P.parent()
            Ore Function Field in x over Finite Field in t of size 5^3 twisted by t |--> t^5

        A conversion map in the reverse direction is also set::

            sage: Zy(x^(-6) + 2)
            (2*y^2 + 1)/y^2

            sage: Zy(1/x^2)
            Traceback (most recent call last):
            ...
            ValueError: x^(-2) is not in the center

        ABOUT THE DEFAULT NAME OF THE CENTRAL VARIABLE:

        A priori, the default is ``z``.

        However, a variable name is given the first time this method is
        called, the given name become the default for the next calls::

            sage: k.<t> = GF(11^3)
            sage: phi = k.frobenius_endomorphism()
            sage: S.<X> = k['X', phi]
            sage: K = S.fraction_field()

            sage: C.<u> = K.center()  # first call
            sage: C
            Fraction Field of Univariate Polynomial Ring in u over Finite Field of size 11
            sage: K.center()  # second call: the variable name is still u
            Fraction Field of Univariate Polynomial Ring in u over Finite Field of size 11

        We can update the default variable name by passing in the argument
        ``default=True``::

            sage: D.<v> = K.center(default=True)
            sage: D
            Fraction Field of Univariate Polynomial Ring in v over Finite Field of size 11
            sage: K.center()
            Fraction Field of Univariate Polynomial Ring in v over Finite Field of size 11
        """
        if name is not None and names is not None:
            raise ValueError("you must specify the name of the variable")
        if names is None:
            if name is None:
                name = self._center_variable_name
            if name is None:
                name = 'z'
            names = (name,)
        names = normalize_names(1, names)
        name = names[0]
        if name in self._center:
            center = self._center[name]
        else:
            ring = self._ring
            ringcenter = ring.center(name, default=False)
            ringembed = ring.coerce_map_from(ringcenter)
            center = ringcenter.fraction_field()
            embed = OreFunctionCenterInjection(center, self, ringembed)
            try:
                assert not self.has_coerce_map_from(center)
                self.register_coercion(embed)
                center.register_conversion(embed.section())
            except AssertionError:
                raise ValueError("creation of coercion map fails; consider using another variable name")
            self._center[name] = center
        if default or (self._center_variable_name is None):
            self._center_variable_name = name
        return center
Example #30
0
    def create_key(self,base_ring, arg1=None, arg2=None,
                                      sparse=False, order='degrevlex',
                                      names=None, name=None,
                                      implementation=None, degrees=None):
        """
        Create the key under which a free algebra is stored.

        TESTS::

            sage: FreeAlgebra.create_key(GF(5),['x','y','z'])
            (Finite Field of size 5, ('x', 'y', 'z'))
            sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3)
            (Finite Field of size 5, ('x', 'y', 'z'))
            sage: FreeAlgebra.create_key(GF(5),3,'xyz')
            (Finite Field of size 5, ('x', 'y', 'z'))
            sage: FreeAlgebra.create_key(GF(5),['x','y','z'], implementation='letterplace')
            (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
            sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3, implementation='letterplace')
            (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
            sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace')
            (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
            sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace', degrees=[1,2,3])
            ((1, 2, 3), Multivariate Polynomial Ring in x, y, z, x_ over Finite Field of size 5)

        """
        if arg1 is None and arg2 is None and names is None:
            # this is used for pickling
            if degrees is None:
                return (base_ring,)
            return tuple(degrees),base_ring
        PolRing = None
        # test if we can use libSingular/letterplace
        if implementation is not None and implementation != 'generic':
            try:
                PolRing = PolynomialRing(base_ring, arg1, arg2,
                                   sparse=sparse, order=order,
                                   names=names, name=name,
                                   implementation=implementation if implementation != 'letterplace' else None)
                if not isinstance(PolRing, MPolynomialRing_libsingular):
                    if PolRing.ngens() == 1:
                        PolRing = PolynomialRing(base_ring, 1, PolRing.variable_names())
                        if not isinstance(PolRing, MPolynomialRing_libsingular):
                            raise TypeError
                    else:
                        raise TypeError
            except (TypeError, NotImplementedError) as msg:
                raise NotImplementedError("The letterplace implementation is not available for the free algebra you requested")
        if PolRing is not None:
            if degrees is None:
                return (PolRing,)
            from sage.all import TermOrder
            T = PolRing.term_order() + TermOrder('lex',1)
            varnames = list(PolRing.variable_names())
            newname = 'x'
            while newname in varnames:
                newname += '_'
            varnames.append(newname)
            return tuple(degrees),PolynomialRing(PolRing.base(), varnames,
                    sparse=sparse, order=T,
                    implementation=implementation if implementation != 'letterplace' else None)
        # normalise the generator names
        from sage.all import Integer
        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 arg2 is None:
            arg2 = len(arg1)
        names = normalize_names(arg2, arg1)
        return base_ring, names
Example #31
0
def standardize_names_index_set(names=None, index_set=None, ngens=None):
    """
    Standardize the ``names`` and ``index_set`` inputs.

    INPUT:

    - ``names`` -- (optional) the variable names
    - ``index_set`` -- (optional) the index set
    - ``ngens`` -- (optional) the number of generators

    If ``ngens`` is a negative number, then this does not check that
    the number of variable names matches the size of the index set.

    OUTPUT:

    A pair ``(names_std, index_set_std)``, where ``names_std`` is either
    ``None`` or a tuple of strings, and where ``index_set_std`` is a finite
    enumerated set.
    The purpose of ``index_set_std`` is to index the generators of some object
    (e.g., the basis of a module); the strings in ``names_std``, when they
    exist, are used for printing these indices. The ``ngens``

    If ``names`` contains exactly one name ``X`` and ``ngens`` is greater than
    1, then ``names_std`` are ``Xi`` for ``i`` in ``range(ngens)``.

    TESTS::

        sage: from sage.structure.indexed_generators import standardize_names_index_set
        sage: standardize_names_index_set('x,y')
        (('x', 'y'), {'x', 'y'})
        sage: standardize_names_index_set(['x','y'])
        (('x', 'y'), {'x', 'y'})
        sage: standardize_names_index_set(['x','y'], ['a','b'])
        (('x', 'y'), {'a', 'b'})
        sage: standardize_names_index_set('x,y', ngens=2)
        (('x', 'y'), {'x', 'y'})
        sage: standardize_names_index_set(index_set=['a','b'], ngens=2)
        (None, {'a', 'b'})
        sage: standardize_names_index_set('x', ngens=3)
        (('x0', 'x1', 'x2'), {'x0', 'x1', 'x2'})

        sage: standardize_names_index_set()
        Traceback (most recent call last):
        ...
        ValueError: the index_set, names, or number of generators must be specified
        sage: standardize_names_index_set(['x'], ['a', 'b'])
        Traceback (most recent call last):
        ...
        IndexError: the number of names must equal the size of the indexing set
        sage: standardize_names_index_set('x,y', ['a'])
        Traceback (most recent call last):
        ...
        IndexError: the number of names must equal the size of the indexing set
        sage: standardize_names_index_set('x,y,z', ngens=2)
        Traceback (most recent call last):
        ...
        IndexError: the number of names must equal the number of generators
        sage: standardize_names_index_set(index_set=['a'], ngens=2)
        Traceback (most recent call last):
        ...
        IndexError: the size of the indexing set must equal the number of generators
    """
    if names is not None:
        if ngens is None or ngens < 0:
            names = normalize_names(-1, names)
        else:
            names = normalize_names(ngens, names)

    if index_set is None:
        if names is None:
            # If neither is specified, we make range(ngens) the index set
            if ngens is None:
                raise ValueError("the index_set, names, or number of"
                                 " generators must be specified")
            index_set = tuple(range(ngens))
        else:
            # If only the names are specified, then we make the indexing set
            #   be the names
            index_set = tuple(names)

    from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
    if isinstance(index_set,
                  dict):  # dict of {name: index} -- not likely to be used
        if names is not None:
            raise ValueError("cannot give index_set as a dict and names")
        names = normalize_names(-1, tuple(index_set.keys()))
        index_set = FiniteEnumeratedSet([index_set[n] for n in names])
    elif isinstance(index_set, str):
        index_set = FiniteEnumeratedSet(list(index_set))
    elif isinstance(index_set, (tuple, list)):
        index_set = FiniteEnumeratedSet(index_set)

    if ngens is None or ngens >= 0:
        if names is not None:
            if len(names) != index_set.cardinality():
                raise IndexError("the number of names must equal"
                                 " the size of the indexing set")
            if ngens is not None and len(names) != ngens:
                raise IndexError("the number of names must equal the"
                                 " number of generators")
        elif ngens is not None and index_set.cardinality() != ngens:
            raise IndexError("the size of the indexing set must equal"
                             " the number of generators")

    return (names, index_set)
Example #32
0
def solve_with_extension(monic_polynomial,
                         root_names=None,
                         var='x',
                         flatten=False,
                         warning=True):
    r"""
    Return all roots of a monic polynomial in its base ring or in an appropriate
    extension ring, as far as possible.

    INPUT:

    - ``monic_polynomial`` -- the monic polynomial whose roots should be created
    - ``root_names``  -- names for the indeterminates needed to define the
      splitting algebra of the ``monic_polynomial`` (if necessary and possible)
    - ``var``  -- (default: ``'x'``) for the indeterminate needed to define the
      splitting field of the ``monic_polynomial`` (if necessary and possible)
    - ``flatten`` -- (default: ``True``) if ``True`` the roots will not be
      given as a list of pairs ``(root, multiplicity)`` but as a list of
      roots repeated according to their multiplicity
    - ``warning`` -- (default: ``True``) can be used (by setting to ``False``)
      to suppress a warning which will be thrown whenever it cannot be checked
      that the Galois group of ``monic_polynomial`` is maximal

    OUTPUT:

    List of tuples ``(root, multiplicity)`` respectively list of roots repeated
    according to their multiplicity if option ``flatten`` is ``True``.

    EXAMPLES::

        sage: from sage.algebras.splitting_algebra import solve_with_extension
        sage: t = polygen(ZZ)
        sage: p = t^2 -2*t +1
        sage: solve_with_extension(p, flatten=True )
        [1, 1]
        sage: solve_with_extension(p)
        [(1, 2)]

        sage: cp5 = cyclotomic_polynomial(5, var='T').change_ring(UniversalCyclotomicField())
        sage: solve_with_extension(cp5)
        [(E(5), 1), (E(5)^4, 1), (E(5)^2, 1), (E(5)^3, 1)]
        sage: _[0][0].parent()
        Universal Cyclotomic Field
    """
    def create_roots(monic_polynomial, warning=True):
        r"""
        This internal function creates all roots of a polynomial in an
        appropriate extension ring assuming that none of the roots is
        contained its base ring.

        It first tries to create the splitting field of the given polynomial.
        If this is not faithful the splitting algebra will be created.

        INPUT:

        - ``monic_polynomial`` -- the monic polynomial whose roots should
          be created
        - ``warning`` -- (default: ``True``) can be used (by setting to ``False``)
          to suppress a warning which will be thrown whenever it cannot be
          checked that the Galois group of ``monic_polynomial`` is maximal
        """
        parent = monic_polynomial.parent()
        base_ring = parent.base_ring()

        try:
            ext_field, embed = monic_polynomial.splitting_field(var, map=True)

            if embed.domain() != base_ring:
                # in this case the SplittingAlgebra is preferred
                raise NotImplementedError

            # -------------------------------------------------------------------------------------
            # in some cases the embedding of the base_ring in ext_field can not be obtained
            # as coercion
            # -------------------------------------------------------------------------------------
            reset_coercion = False
            from sage.rings.number_field.number_field import NumberField_generic
            if isinstance(base_ring, NumberField_generic):
                reset_coercion = True
            elif base_ring.is_finite() and not base_ring.is_prime_field():
                reset_coercion = True
            if reset_coercion:
                ext_field._unset_coercions_used()
                ext_field.register_coercion(embed)
                ext_field.register_conversion(embed)

            verbose("splitting field %s defined" % (ext_field))
            pol_emb = monic_polynomial.change_ring(ext_field)
            roots = pol_emb.roots()
        except NotImplementedError:
            ext_ring = SplittingAlgebra(monic_polynomial,
                                        name_list,
                                        warning=warning)
            verbose("splitting algebra %s defined" % (ext_ring))
            roots = [(r, 1) for r in ext_ring.splitting_roots()]
        return roots

    deg_pol = monic_polynomial.degree()
    if not root_names:
        from sage.structure.category_object import normalize_names
        root_names = normalize_names(deg_pol - 1, 'r')
    name_list = list(root_names)
    root_list = []
    try:
        root_list = monic_polynomial.roots()
    except (TypeError, ValueError, NotImplementedError):
        pass

    if not root_list:
        # ------------------------------------------------------------------------------
        # no roots found: find roots in an appropriate extension ring
        # ------------------------------------------------------------------------------
        verbose("no roots in base_ring")
        if len(name_list) > deg_pol - 1:
            name_list = [name_list[i] for i in range(deg_pol - 1)]
        roots = create_roots(monic_polynomial, warning=warning)

    else:
        # ------------------------------------------------------------------------------
        # root calculation was possible but maybe some more roots in an apropriate
        # extension ring can be constructed.
        # ------------------------------------------------------------------------------
        num_roots = sum(m for r, m in root_list)
        if num_roots < deg_pol:
            h = monic_polynomial.variables()[0]
            divisor = monic_polynomial.base_ring().one()
            for r, m in root_list:
                divisor *= (h - r)**m
            q, r = monic_polynomial.quo_rem(divisor)
            if len(name_list) > deg_pol - num_roots - 1:
                name_list = [
                    name_list[i] for i in range(deg_pol - num_roots - 1)
                ]
            verbose("%d root found in base ring, now solving %s" %
                    (num_roots, q))
            missing_roots = create_roots(q, warning=True)
            roots = root_list + missing_roots
        else:
            roots = root_list
            verbose("all roots in base ring")

    if flatten:
        from sage.misc.flatten import flatten
        return flatten([[rt] * m for rt, m in roots])
    return roots
Example #33
0
def FreeGroup(n=None, names='x', index_set=None, abelian=False, **kwds):
    """
    Construct a Free Group.

    INPUT:

    - ``n`` -- integer or ``None`` (default). The nnumber of
      generators. If not specified the ``names`` are counted.

    - ``names`` -- string or list/tuple/iterable of strings (default:
      ``'x'``). The generator names or name prefix.

    - ``index_set`` -- (optional) an index set for the generators; if
      specified then the optional keyword ``abelian`` can be used

    - ``abelian`` -- (default: ``False``) whether to construct a free
      abelian group or a free group

    .. NOTE::

        If you want to create a free group, it is currently preferential to
        use ``Groups().free(...)`` as that does not load GAP.

    EXAMPLES::

        sage: G.<a,b> = FreeGroup();  G
        Free Group on generators {a, b}
        sage: H = FreeGroup('a, b')
        sage: G is H
        True
        sage: FreeGroup(0)
        Free Group on generators {}

    The entry can be either a string with the names of the generators,
    or the number of generators and the prefix of the names to be
    given. The default prefix is ``'x'`` ::

        sage: FreeGroup(3)
        Free Group on generators {x0, x1, x2}
        sage: FreeGroup(3, 'g')
        Free Group on generators {g0, g1, g2}
        sage: FreeGroup()
        Free Group on generators {x}

    We give two examples using the ``index_set`` option::

        sage: FreeGroup(index_set=ZZ)
        Free group indexed by Integer Ring
        sage: FreeGroup(index_set=ZZ, abelian=True)
        Free abelian group indexed by Integer Ring

    TESTS::

        sage: G1 = FreeGroup(2, 'a,b')
        sage: G2 = FreeGroup('a,b')
        sage: G3.<a,b> = FreeGroup()
        sage: G1 is G2, G2 is G3
        (True, True)
    """
    # Support Freegroup('a,b') syntax
    if n is not None:
        try:
            n = Integer(n)
        except TypeError:
            names = n
            n = None
    # derive n from counting names
    if n is None:
        if isinstance(names, six.string_types):
            n = len(names.split(','))
        else:
            names = list(names)
            n = len(names)
    from sage.structure.category_object import normalize_names
    names = normalize_names(n, names)
    if index_set is not None or abelian:
        if abelian:
            from sage.groups.indexed_free_group import IndexedFreeAbelianGroup
            return IndexedFreeAbelianGroup(index_set, names=names, **kwds)

        from sage.groups.indexed_free_group import IndexedFreeGroup
        return IndexedFreeGroup(index_set, names=names, **kwds)
    return FreeGroup_class(names)
def _single_variate(base_ring, name, sparse, implementation):
    import sage.rings.polynomial.polynomial_ring as m
    name = normalize_names(1, name)
    key = (base_ring, name, sparse, implementation if not sparse else None)
    R = _get_from_cache(key)
    if not R is None:
        return R

    if isinstance(base_ring, ring.CommutativeRing):
        if is_IntegerModRing(base_ring) and not sparse:
            n = base_ring.order()
            if n.is_prime():
                R = m.PolynomialRing_dense_mod_p(base_ring,
                                                 name,
                                                 implementation=implementation)
            elif n > 1:
                R = m.PolynomialRing_dense_mod_n(base_ring,
                                                 name,
                                                 implementation=implementation)
            else:  # n == 1!
                R = m.PolynomialRing_integral_domain(
                    base_ring, name)  # specialized code breaks in this case.

        elif is_FiniteField(base_ring) and not sparse:
            R = m.PolynomialRing_dense_finite_field(
                base_ring, name, implementation=implementation)

        elif isinstance(base_ring, padic_base_leaves.pAdicFieldCappedRelative):
            R = m.PolynomialRing_dense_padic_field_capped_relative(
                base_ring, name)

        elif isinstance(base_ring, padic_base_leaves.pAdicRingCappedRelative):
            R = m.PolynomialRing_dense_padic_ring_capped_relative(
                base_ring, name)

        elif isinstance(base_ring, padic_base_leaves.pAdicRingCappedAbsolute):
            R = m.PolynomialRing_dense_padic_ring_capped_absolute(
                base_ring, name)

        elif isinstance(base_ring, padic_base_leaves.pAdicRingFixedMod):
            R = m.PolynomialRing_dense_padic_ring_fixed_mod(base_ring, name)

        elif base_ring in _CompleteDiscreteValuationRings:
            R = m.PolynomialRing_cdvr(base_ring, name, sparse)

        elif base_ring in _CompleteDiscreteValuationFields:
            R = m.PolynomialRing_cdvf(base_ring, name, sparse)

        elif base_ring.is_field(proof=False):
            R = m.PolynomialRing_field(base_ring, name, sparse)

        elif base_ring.is_integral_domain(proof=False):
            R = m.PolynomialRing_integral_domain(base_ring, name, sparse,
                                                 implementation)
        else:
            R = m.PolynomialRing_commutative(base_ring, name, sparse)
    else:
        R = m.PolynomialRing_general(base_ring, name, sparse)

    if hasattr(R, '_implementation_names'):
        for name in R._implementation_names:
            real_key = key[0:3] + (name, )
            _save_in_cache(real_key, R)
    else:
        _save_in_cache(key, R)
    return R
Example #35
0
    def create_key(self,
                   base_ring,
                   arg1=None,
                   arg2=None,
                   sparse=None,
                   order='degrevlex',
                   names=None,
                   name=None,
                   implementation=None,
                   degrees=None):
        """
        Create the key under which a free algebra is stored.

        TESTS::

            sage: FreeAlgebra.create_key(GF(5),['x','y','z'])
            (Finite Field of size 5, ('x', 'y', 'z'))
            sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3)
            (Finite Field of size 5, ('x', 'y', 'z'))
            sage: FreeAlgebra.create_key(GF(5),3,'xyz')
            (Finite Field of size 5, ('x', 'y', 'z'))
            sage: FreeAlgebra.create_key(GF(5),['x','y','z'], implementation='letterplace')
            (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
            sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3, implementation='letterplace')
            (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
            sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace')
            (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
            sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace', degrees=[1,2,3])
            ((1, 2, 3), Multivariate Polynomial Ring in x, y, z, x_ over Finite Field of size 5)

        """
        if arg1 is None and arg2 is None and names is None:
            # this is used for pickling
            if degrees is None:
                return (base_ring, )
            return tuple(degrees), base_ring
        # test if we can use libSingular/letterplace
        if implementation == "letterplace":
            args = [arg for arg in (arg1, arg2) if arg is not None]
            kwds = dict(sparse=sparse, order=order, implementation="singular")
            if name is not None:
                kwds["name"] = name
            if names is not None:
                kwds["names"] = names
            PolRing = PolynomialRing(base_ring, *args, **kwds)
            if degrees is None:
                return (PolRing, )
            from sage.all import TermOrder
            T = PolRing.term_order() + TermOrder('lex', 1)
            varnames = list(PolRing.variable_names())
            newname = 'x'
            while newname in varnames:
                newname += '_'
            varnames.append(newname)
            R = PolynomialRing(PolRing.base(),
                               varnames,
                               sparse=sparse,
                               order=T)
            return tuple(degrees), R
        # normalise the generator names
        from sage.all import Integer
        if isinstance(arg1, (Integer, int)):
            arg1, arg2 = arg2, arg1
        if not names is None:
            arg1 = names
        elif not name is None:
            arg1 = name
        if arg2 is None:
            arg2 = len(arg1)
        names = normalize_names(arg2, arg1)
        return base_ring, names
Example #36
0
def PowerSeriesRing(base_ring, name=None, arg2=None, names=None,
                    sparse=False, default_prec=None, order='negdeglex',
                    num_gens=None, implementation=None):
    r"""
    Create a univariate or multivariate power series ring over a given
    (commutative) base ring.

    INPUT:


    -  ``base_ring`` - a commutative ring

    -  ``name``, ``names`` - name(s) of the indeterminate

    - ``default_prec`` - the default precision used if an exact object must
       be changed to an approximate object in order to do an arithmetic
       operation.  If left as ``None``, it will be set to the global
       default (20) in the univariate case, and 12 in the multivariate case.

    -  ``sparse`` - (default: ``False``) whether power series
       are represented as sparse objects.

    - ``order`` - (default: ``negdeglex``) term ordering, for multivariate case

    - ``num_gens`` - number of generators, for multivariate case


    There is a unique power series ring over each base ring with given
    variable name. Two power series over the same base ring with
    different variable names are not equal or isomorphic.

    EXAMPLES (Univariate)::

        sage: R = PowerSeriesRing(QQ, 'x'); R
        Power Series Ring in x over Rational Field

    ::

        sage: S = PowerSeriesRing(QQ, 'y'); S
        Power Series Ring in y over Rational Field

    ::

        sage: R = PowerSeriesRing(QQ, 10)
        Traceback (most recent call last):
        ...
        ValueError: variable name '10' does not start with a letter

    ::

        sage: S = PowerSeriesRing(QQ, 'x', default_prec = 15); S
        Power Series Ring in x over Rational Field
        sage: S.default_prec()
        15

    EXAMPLES (Multivariate) See also :doc:`multi_power_series_ring`::

        sage: R = PowerSeriesRing(QQ, 't,u,v'); R
        Multivariate Power Series Ring in t, u, v over Rational Field

    ::

        sage: N = PowerSeriesRing(QQ,'w',num_gens=5); N
        Multivariate Power Series Ring in w0, w1, w2, w3, w4 over Rational Field

    Number of generators can be specified before variable name without using keyword::

        sage: M = PowerSeriesRing(QQ,4,'k'); M
        Multivariate Power Series Ring in k0, k1, k2, k3 over Rational Field

    Multivariate power series can be constructed using angle bracket or double square bracket notation::

        sage: R.<t,u,v> = PowerSeriesRing(QQ, 't,u,v'); R
        Multivariate Power Series Ring in t, u, v over Rational Field

        sage: ZZ[['s,t,u']]
        Multivariate Power Series Ring in s, t, u over Integer Ring

    Sparse multivariate power series ring::

        sage: M = PowerSeriesRing(QQ,4,'k',sparse=True); M
        Sparse Multivariate Power Series Ring in k0, k1, k2, k3 over
        Rational Field

    Power series ring over polynomial ring::

        sage: H = PowerSeriesRing(PolynomialRing(ZZ,3,'z'),4,'f'); H
        Multivariate Power Series Ring in f0, f1, f2, f3 over Multivariate
        Polynomial Ring in z0, z1, z2 over Integer Ring

    Power series ring over finite field::

        sage: S = PowerSeriesRing(GF(65537),'x,y'); S
        Multivariate Power Series Ring in x, y over Finite Field of size
        65537

    Power series ring with many variables::

        sage: R = PowerSeriesRing(ZZ, ['x%s'%p for p in primes(100)]); R
        Multivariate Power Series 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

    - Use :meth:`inject_variables` to make the variables 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: f = x47 + 3*x11*x29 - x19 + R.O(3)
        sage: f in R
        True


    Variable ordering determines how series are displayed::

        sage: T.<a,b> = PowerSeriesRing(ZZ,order='deglex'); T
        Multivariate Power Series Ring in a, b over Integer Ring
        sage: T.term_order()
        Degree lexicographic term order
        sage: p = - 2*b^6 + a^5*b^2 + a^7 - b^2 - a*b^3 + T.O(9); p
        a^7 + a^5*b^2 - 2*b^6 - a*b^3 - b^2 + O(a, b)^9

        sage: U = PowerSeriesRing(ZZ,'a,b',order='negdeglex'); U
        Multivariate Power Series Ring in a, b over Integer Ring
        sage: U.term_order()
        Negative degree lexicographic term order
        sage: U(p)
        -b^2 - a*b^3 - 2*b^6 + a^7 + a^5*b^2 + O(a, b)^9


    TESTS::

        sage: N = PowerSeriesRing(QQ,'k',num_gens=5); N
        Multivariate Power Series Ring in k0, k1, k2, k3, k4 over Rational Field

    The following behavior of univariate power series ring will eventually
    be deprecated and then changed to return a multivariate power series
    ring::

        sage: N = PowerSeriesRing(QQ,'k',5); N
        Power Series Ring in k over Rational Field
        sage: N.default_prec()
        5
        sage: L.<m> = PowerSeriesRing(QQ,5); L
        Power Series Ring in m over Rational Field
        sage: L.default_prec()
        5

    By :trac:`14084`, a power series ring belongs to the category of integral
    domains, if the base ring does::

        sage: P = ZZ[['x']]
        sage: P.category()
        Category of integral domains
        sage: TestSuite(P).run()
        sage: M = ZZ[['x','y']]
        sage: M.category()
        Category of integral domains
        sage: TestSuite(M).run()

    Otherwise, it belongs to the category of commutative rings::

        sage: P = Integers(15)[['x']]
        sage: P.category()
        Category of commutative rings
        sage: TestSuite(P).run()
        sage: M = Integers(15)[['x','y']]
        sage: M.category()
        Category of commutative rings
        sage: TestSuite(M).run()

    .. SEEALSO::

        * :func:`sage.misc.defaults.set_series_precision`
    """
    #multivariate case:
    # examples for first case:
    # PowerSeriesRing(QQ,'x,y,z')
    # PowerSeriesRing(QQ,['x','y','z'])
    # PowerSeriesRing(QQ,['x','y','z'], 3)
    if names is None and name is not None:
        names = name
    if isinstance(names, (tuple, list)) and len(names) > 1 or (isinstance(names, str) and ',' in names):
        return _multi_variate(base_ring, num_gens=arg2, names=names,
                     order=order, default_prec=default_prec, sparse=sparse)
    # examples for second case:
    # PowerSeriesRing(QQ,3,'t')
    if arg2 is None and num_gens is not None:
        arg2 = names
        names = num_gens
    if (isinstance(arg2, str) and
            isinstance(names, integer_types + (integer.Integer,))):
        return _multi_variate(base_ring, num_gens=names, names=arg2,
                     order=order, default_prec=default_prec, sparse=sparse)


    # univariate case: the arguments to PowerSeriesRing used to be
    # (base_ring, name=None, default_prec=20, names=None, sparse=False),
    # and thus that is what the code below expects; this behavior is being
    # deprecated, and will eventually be removed.
    if default_prec is None and arg2 is None:
        from sage.misc.defaults import series_precision
        default_prec = series_precision()
    elif arg2 is not None:
        default_prec = arg2

    ## too many things (padics, elliptic curves) depend on this behavior,
    ## so no warning for now.
    ##
    # from sage.misc.superseded import deprecation
    # if isinstance(name, (int,integer.Integer)) or isinstance(arg2,(int,integer.Integer)):
    #     deprecation(trac_number, "This behavior of PowerSeriesRing is being deprecated in favor of constructing multivariate power series rings. (See Trac ticket #1956.)")


    # the following is the original, univariate-only code

    if isinstance(name, integer_types + (integer.Integer,)):
        default_prec = name
    if not names is None:
        name = names
    name = normalize_names(1, name)

    if name is None:
        raise TypeError("You must specify the name of the indeterminate of the Power series ring.")

    key = (base_ring, name, default_prec, sparse, implementation)
    if PowerSeriesRing_generic.__classcall__.is_in_cache(key):
        return PowerSeriesRing_generic(*key)

    if isinstance(name, (tuple, list)):
        assert len(name) == 1
        name = name[0]

    if not (name is None or isinstance(name, str)):
        raise TypeError("variable name must be a string or None")

    if base_ring in _Fields:
        R = PowerSeriesRing_over_field(base_ring, name, default_prec,
                                       sparse=sparse, implementation=implementation)
    elif base_ring in _IntegralDomains:
        R = PowerSeriesRing_domain(base_ring, name, default_prec,
                                   sparse=sparse, implementation=implementation)
    elif base_ring in _CommutativeRings:
        R = PowerSeriesRing_generic(base_ring, name, default_prec,
                                    sparse=sparse, implementation=implementation)
    else:
        raise TypeError("base_ring must be a commutative ring")
    return R
Example #37
0
    def center(self, name=None, names=None, default=False):
        r"""
        Return the center of this skew polynomial ring.

        .. NOTE::

            If `F` denotes the subring of `R` fixed by `\sigma` and `\sigma`
            has order `r`, the center of `K[x,\sigma]` is `F[x^r]`, that
            is a univariate polynomial ring over `F`.

        INPUT:

        - ``name`` -- a string or ``None`` (default: ``None``);
          the name for the central variable (namely `x^r`)

        - ``default`` -- a boolean (default: ``False``); if ``True``,
          set the default variable name for the center to ``name``

        EXAMPLES::

            sage: k.<t> = GF(5^3)
            sage: Frob = k.frobenius_endomorphism()
            sage: S.<x> = k['x',Frob]; S
            Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5

            sage: Z = S.center(); Z
            Univariate Polynomial Ring in z over Finite Field of size 5
            sage: Z.gen()
            z

        We can pass in another variable name::

            sage: S.center(name='y')
            Univariate Polynomial Ring in y over Finite Field of size 5

        or use the bracket notation::

            sage: Zy.<y> = S.center(); Zy
            Univariate Polynomial Ring in y over Finite Field of size 5
            sage: y.parent() is Zy
            True

        A coercion map from the center to the skew polynomial ring is set::

            sage: S.has_coerce_map_from(Zy)
            True

            sage: P = y + x; P
            x^3 + x
            sage: P.parent()
            Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5
            sage: P.parent() is S
            True

        together with a conversion map in the reverse direction::

            sage: Zy(x^6 + 2*x^3 + 3)
            y^2 + 2*y + 3

            sage: Zy(x^2)
            Traceback (most recent call last):
            ...
            ValueError: x^2 is not in the center

        Two different skew polynomial rings can share the same center::

            sage: S1.<x1> = k['x1', Frob]
            sage: S2.<x2> = k['x2', Frob]
            sage: S1.center() is S2.center()
            True

        .. RUBRIC:: About the default name of the central variable

        A priori, the default is ``z``.

        However, a variable name is given the first time this method is
        called, the given name become the default for the next calls::

            sage: K.<t> = GF(11^3)
            sage: phi = K.frobenius_endomorphism()
            sage: A.<X> = K['X', phi]

            sage: C.<u> = A.center()  # first call
            sage: C
            Univariate Polynomial Ring in u over Finite Field of size 11
            sage: A.center()  # second call: the variable name is still u
            Univariate Polynomial Ring in u over Finite Field of size 11
            sage: A.center() is C
            True

        We can update the default variable name by passing in the argument
        ``default=True``::

            sage: D.<v> = A.center(default=True)
            sage: D
            Univariate Polynomial Ring in v over Finite Field of size 11
            sage: A.center()
            Univariate Polynomial Ring in v over Finite Field of size 11
            sage: A.center() is D
            True

        TESTS::

            sage: C.<a,b> = S.center()
            Traceback (most recent call last):
            ...
            IndexError: the number of names must equal the number of generators
        """
        if name is not None and names is not None:
            raise ValueError("you must specify the name of the variable")
        if names is None:
            if name is None:
                name = self._center_variable_name
            if name is None:
                name = 'z'
            names = (name, )
        names = normalize_names(1, names)
        name = names[0]
        if name in self._center:
            center = self._center[name]
        else:
            center = PolynomialRing(self._constants, names)
            embed = SkewPolynomialCenterInjection(center, self,
                                                  self._embed_constants,
                                                  self._order)
            try:
                assert not self.has_coerce_map_from(center)
                self.register_coercion(embed)
                center.register_conversion(embed.section())
            except AssertionError:
                raise ValueError(
                    "creation of coercion map fails; consider using another variable name"
                )
            self._center[name] = center
        if default or (self._center_variable_name is None):
            self._center_variable_name = name
        return center
Example #38
0
    def create_key(self,
                   base,
                   prec=None,
                   log_radii=ZZ(0),
                   names=None,
                   order='degrevlex'):
        """
        Create a key from the input paramaters.

        INPUT:

        - ``base`` -- a `p`-adic ring or field

        - ``prec`` -- an integer or ``None`` (default: ``None``)

        - ``log_radii`` -- an integer or a list or a tuple of integers 
          (default: ``0``)

        - ``names`` -- names of the indeterminates

        - ``order`` - a monomial ordering (default: ``degrevlex``)

        EXAMPLES::

            sage: TateAlgebra.create_key(Zp(2), names=['x','y'])
            (2-adic Field with capped relative precision 20,
             20,
             (0, 0),
             ('x', 'y'),
             Degree reverse lexicographic term order)

        TESTS::

            sage: TateAlgebra.create_key(Zp(2))
            Traceback (most recent call last):
            ...
            ValueError: you must specify the names of the variables
            sage: TateAlgebra.create_key(ZZ)
            Traceback (most recent call last):
            ...
            TypeError: the base ring must be a p-adic ring or a p-adic field
            sage: TateAlgebra.create_key(Zp(2), names=['x','y'], log_radii=[1])
            Traceback (most recent call last):
            ...
            ValueError: the number of radii does not match the number of variables
            sage: TateAlgebra.create_key(Zp(2), names=['x','y'], log_radii=[0, 1/2])
            Traceback (most recent call last):
            ...
            NotImplementedError: only integral log_radii are implemented
            sage: TateAlgebra.create_key(Zp(2), names=['x','y'], order='myorder')
            Traceback (most recent call last):
            ...
            ValueError: unknown term order 'myorder'

        """
        if not isinstance(base, pAdicGeneric):
            raise TypeError(
                "the base ring must be a p-adic ring or a p-adic field")
        # TODO: allow for arbitrary CDVF
        base = base.fraction_field()
        if names is None:
            raise ValueError("you must specify the names of the variables")
        names = normalize_names(-1, names)
        ngens = len(names)
        if not isinstance(log_radii, (list, tuple)):
            try:
                log_radii = [ZZ(log_radii)] * ngens
            except TypeError:
                raise NotImplementedError(
                    "only integral log_radii are implemented")
        elif len(log_radii) != ngens:
            raise ValueError(
                "the number of radii does not match the number of variables")
        else:
            try:
                log_radii = [ZZ(r) for r in log_radii]
            except TypeError:
                raise NotImplementedError(
                    "only integral log_radii are implemented")
        order = TermOrder(order, ngens)
        if prec is None:
            prec = base.precision_cap()
        key = (base, prec, tuple(log_radii), names, order)
        return key
Example #39
0
def standardize_names_index_set(names=None, index_set=None, ngens=None):
    """
    Standardize the ``names`` and ``index_set`` inputs.

    INPUT:

    - ``names`` -- (optional) the variable names
    - ``index_set`` -- (optional) the index set
    - ``ngens`` -- (optional) the number of generators

    If ``ngens`` is a negative number, then this does not check that
    the number of variable names matches the size of the index set.

    OUTPUT:

    A pair ``(names_std, index_set_std)``, where ``names_std`` is either
    ``None`` or a tuple of strings, and where ``index_set_std`` is a finite
    enumerated set.
    The purpose of ``index_set_std`` is to index the generators of some object
    (e.g., the basis of a module); the strings in ``names_std``, when they
    exist, are used for printing these indices. The ``ngens``

    If ``names`` contains exactly one name ``X`` and ``ngens`` is greater than
    1, then ``names_std`` are ``Xi`` for ``i`` in ``range(ngens)``.

    TESTS::

        sage: from sage.structure.indexed_generators import standardize_names_index_set
        sage: standardize_names_index_set('x,y')
        (('x', 'y'), {'x', 'y'})
        sage: standardize_names_index_set(['x','y'])
        (('x', 'y'), {'x', 'y'})
        sage: standardize_names_index_set(['x','y'], ['a','b'])
        (('x', 'y'), {'a', 'b'})
        sage: standardize_names_index_set('x,y', ngens=2)
        (('x', 'y'), {'x', 'y'})
        sage: standardize_names_index_set(index_set=['a','b'], ngens=2)
        (None, {'a', 'b'})
        sage: standardize_names_index_set('x', ngens=3)
        (('x0', 'x1', 'x2'), {'x0', 'x1', 'x2'})

        sage: standardize_names_index_set()
        Traceback (most recent call last):
        ...
        ValueError: the index_set, names, or number of generators must be specified
        sage: standardize_names_index_set(['x'], ['a', 'b'])
        Traceback (most recent call last):
        ...
        IndexError: the number of names must equal the size of the indexing set
        sage: standardize_names_index_set('x,y', ['a'])
        Traceback (most recent call last):
        ...
        IndexError: the number of names must equal the size of the indexing set
        sage: standardize_names_index_set('x,y,z', ngens=2)
        Traceback (most recent call last):
        ...
        IndexError: the number of names must equal the number of generators
        sage: standardize_names_index_set(index_set=['a'], ngens=2)
        Traceback (most recent call last):
        ...
        IndexError: the size of the indexing set must equal the number of generators
    """
    if names is not None:
        if ngens is None or ngens < 0:
            names = normalize_names(-1, names)
        else:
            names = normalize_names(ngens, names)

    if index_set is None:
        if names is None:
            # If neither is specified, we make range(ngens) the index set
            if ngens is None:
                raise ValueError("the index_set, names, or number of"
                                 " generators must be specified")
            index_set = tuple(range(ngens))
        else:
            # If only the names are specified, then we make the indexing set
            #   be the names
            index_set = tuple(names)

    from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
    if isinstance(index_set, dict): # dict of {name: index} -- not likely to be used
        if names is not None:
            raise ValueError("cannot give index_set as a dict and names")
        names = normalize_names(-1, tuple(index_set.keys()))
        index_set = FiniteEnumeratedSet([index_set[n] for n in names])
    elif isinstance(index_set, str):
        index_set = FiniteEnumeratedSet(list(index_set))
    elif isinstance(index_set, (tuple, list)):
        index_set = FiniteEnumeratedSet(index_set)

    if ngens is None or ngens >= 0:
        if names is not None:
            if len(names) != index_set.cardinality():
                raise IndexError("the number of names must equal"
                                 " the size of the indexing set")
            if ngens is not None and len(names) != ngens:
                raise IndexError("the number of names must equal the"
                                 " number of generators")
        elif ngens is not None and index_set.cardinality() != ngens:
            raise IndexError("the size of the indexing set must equal"
                             " the number of generators")

    return (names, index_set)
Example #40
0
def PowerSeriesRing(base_ring,
                    name=None,
                    arg2=None,
                    names=None,
                    sparse=False,
                    default_prec=None,
                    order='negdeglex',
                    num_gens=None):
    r"""
    Create a univariate or multivariate power series ring over a given
    (commutative) base ring.

    INPUT:


    -  ``base_ring`` - a commutative ring

    -  ``name``, ``names`` - name(s) of the indeterminate

    - ``default_prec`` - the default precision used if an exact object must
       be changed to an approximate object in order to do an arithmetic
       operation.  If left as ``None``, it will be set to the global
       default (20) in the univariate case, and 12 in the multivariate case.

    -  ``sparse`` - (default: ``False``) whether power series
       are represented as sparse objects.

    - ``order`` - (default: ``negdeglex``) term ordering, for multivariate case

    - ``num_gens`` - number of generators, for multivariate case


    There is a unique power series ring over each base ring with given
    variable name. Two power series over the same base ring with
    different variable names are not equal or isomorphic.

    EXAMPLES (Univariate)::

        sage: R = PowerSeriesRing(QQ, 'x'); R
        Power Series Ring in x over Rational Field

    ::

        sage: S = PowerSeriesRing(QQ, 'y'); S
        Power Series Ring in y over Rational Field

    ::

        sage: R = PowerSeriesRing(QQ, 10)
        Traceback (most recent call last):
        ...
        ValueError: variable name '10' does not start with a letter

    ::

        sage: S = PowerSeriesRing(QQ, 'x', default_prec = 15); S
        Power Series Ring in x over Rational Field
        sage: S.default_prec()
        15

    EXAMPLES (Multivariate) See also :doc:`multi_power_series_ring`::

        sage: R = PowerSeriesRing(QQ, 't,u,v'); R
        Multivariate Power Series Ring in t, u, v over Rational Field

    ::

        sage: N = PowerSeriesRing(QQ,'w',num_gens=5); N
        Multivariate Power Series Ring in w0, w1, w2, w3, w4 over Rational Field

    Number of generators can be specified before variable name without using keyword::

        sage: M = PowerSeriesRing(QQ,4,'k'); M
        Multivariate Power Series Ring in k0, k1, k2, k3 over Rational Field

    Multivariate power series can be constructed using angle bracket or double square bracket notation::

        sage: R.<t,u,v> = PowerSeriesRing(QQ, 't,u,v'); R
        Multivariate Power Series Ring in t, u, v over Rational Field

        sage: ZZ[['s,t,u']]
        Multivariate Power Series Ring in s, t, u over Integer Ring

    Sparse multivariate power series ring::

        sage: M = PowerSeriesRing(QQ,4,'k',sparse=True); M
        Sparse Multivariate Power Series Ring in k0, k1, k2, k3 over
        Rational Field

    Power series ring over polynomial ring::

        sage: H = PowerSeriesRing(PolynomialRing(ZZ,3,'z'),4,'f'); H
        Multivariate Power Series Ring in f0, f1, f2, f3 over Multivariate
        Polynomial Ring in z0, z1, z2 over Integer Ring

    Power series ring over finite field::

        sage: S = PowerSeriesRing(GF(65537),'x,y'); S
        Multivariate Power Series Ring in x, y over Finite Field of size
        65537

    Power series ring with many variables::

        sage: R = PowerSeriesRing(ZZ, ['x%s'%p for p in primes(100)]); R
        Multivariate Power Series 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

    - Use :meth:`inject_variables` to make the variables 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: f = x47 + 3*x11*x29 - x19 + R.O(3)
        sage: f in R
        True


    Variable ordering determines how series are displayed::

        sage: T.<a,b> = PowerSeriesRing(ZZ,order='deglex'); T
        Multivariate Power Series Ring in a, b over Integer Ring
        sage: T.term_order()
        Degree lexicographic term order
        sage: p = - 2*b^6 + a^5*b^2 + a^7 - b^2 - a*b^3 + T.O(9); p
        a^7 + a^5*b^2 - 2*b^6 - a*b^3 - b^2 + O(a, b)^9

        sage: U = PowerSeriesRing(ZZ,'a,b',order='negdeglex'); U
        Multivariate Power Series Ring in a, b over Integer Ring
        sage: U.term_order()
        Negative degree lexicographic term order
        sage: U(p)
        -b^2 - a*b^3 - 2*b^6 + a^7 + a^5*b^2 + O(a, b)^9


    TESTS::

        sage: N = PowerSeriesRing(QQ,'k',num_gens=5); N
        Multivariate Power Series Ring in k0, k1, k2, k3, k4 over Rational Field

    The following behavior of univariate power series ring will eventually
    be deprecated and then changed to return a multivariate power series
    ring::

        sage: N = PowerSeriesRing(QQ,'k',5); N
        Power Series Ring in k over Rational Field
        sage: N.default_prec()
        5
        sage: L.<m> = PowerSeriesRing(QQ,5); L
        Power Series Ring in m over Rational Field
        sage: L.default_prec()
        5

    By :trac:`14084`, a power series ring belongs to the category of integral
    domains, if the base ring does::

        sage: P = ZZ[['x']]
        sage: P.category()
        Category of integral domains
        sage: TestSuite(P).run()
        sage: M = ZZ[['x','y']]
        sage: M.category()
        Category of integral domains
        sage: TestSuite(M).run()

    Otherwise, it belongs to the category of commutative rings::

        sage: P = Integers(15)[['x']]
        sage: P.category()
        Category of commutative rings
        sage: TestSuite(P).run()
        sage: M = Integers(15)[['x','y']]
        sage: M.category()
        Category of commutative rings
        sage: TestSuite(M).run()

    .. SEEALSO::

        * :func:`sage.misc.defaults.set_series_precision`
    """
    #multivariate case:
    # examples for first case:
    # PowerSeriesRing(QQ,'x,y,z')
    # PowerSeriesRing(QQ,['x','y','z'])
    # PowerSeriesRing(QQ,['x','y','z'], 3)
    if names is None and name is not None:
        names = name
    if isinstance(names,
                  (tuple, list)) and len(names) > 1 or (isinstance(names, str)
                                                        and ',' in names):
        return _multi_variate(base_ring,
                              num_gens=arg2,
                              names=names,
                              order=order,
                              default_prec=default_prec,
                              sparse=sparse)
    # examples for second case:
    # PowerSeriesRing(QQ,3,'t')
    if arg2 is None and num_gens is not None:
        arg2 = names
        names = num_gens
    if isinstance(arg2, str) and isinstance(names,
                                            (int, long, integer.Integer)):
        return _multi_variate(base_ring,
                              num_gens=names,
                              names=arg2,
                              order=order,
                              default_prec=default_prec,
                              sparse=sparse)

    # univariate case: the arguments to PowerSeriesRing used to be
    # (base_ring, name=None, default_prec=20, names=None, sparse=False),
    # and thus that is what the code below expects; this behavior is being
    # deprecated, and will eventually be removed.
    if default_prec is None and arg2 is None:
        from sage.misc.defaults import series_precision
        default_prec = series_precision()
    elif arg2 is not None:
        default_prec = arg2

    ## too many things (padics, elliptic curves) depend on this behavior,
    ## so no warning for now.
    ##
    # from sage.misc.superseded import deprecation
    # if isinstance(name, (int,long,integer.Integer)) or isinstance(arg2,(int,long,integer.Integer)):
    #     deprecation(trac_number, "This behavior of PowerSeriesRing is being deprecated in favor of constructing multivariate power series rings. (See Trac ticket #1956.)")

    # the following is the original, univariate-only code

    if isinstance(name, (int, long, integer.Integer)):
        default_prec = name
    if not names is None:
        name = names
    name = normalize_names(1, name)

    if name is None:
        raise TypeError(
            "You must specify the name of the indeterminate of the Power series ring."
        )

    key = (base_ring, name, default_prec, sparse)
    if PowerSeriesRing_generic.__classcall__.is_in_cache(key):
        return PowerSeriesRing_generic(*key)

    if isinstance(name, (tuple, list)):
        assert len(name) == 1
        name = name[0]

    if not (name is None or isinstance(name, str)):
        raise TypeError("variable name must be a string or None")

    if base_ring in _Fields:
        R = PowerSeriesRing_over_field(base_ring,
                                       name,
                                       default_prec,
                                       sparse=sparse)
    elif base_ring in _IntegralDomains:
        R = PowerSeriesRing_domain(base_ring,
                                   name,
                                   default_prec,
                                   sparse=sparse)
    elif base_ring in _CommutativeRings:
        R = PowerSeriesRing_generic(base_ring,
                                    name,
                                    default_prec,
                                    sparse=sparse)
    else:
        raise TypeError("base_ring must be a commutative ring")
    return R
Example #41
0
 def create_key(self, n, names):
     n = int(n)
     names = normalize_names(n, names)
     return (n, names)
Example #42
0
    def __classcall_private__(cls,
                              index_set=None,
                              names=None,
                              commutative=False,
                              **kwds):
        r"""
        Construct a free monoid or a free abelian monoid, depending on the
        input. Also, normalize the input.

        EXAMPLES::

            sage: F.<a,b,c,d,e> = FreeMonoid(); F
            Free monoid on 5 generators (a, b, c, d, e)
            sage: FreeMonoid(index_set=ZZ)
            Free monoid indexed by Integer Ring
            sage: F.<x,y,z> = FreeMonoid(abelian=True); F
            Free abelian monoid on 3 generators (x, y, z)
            sage: FreeMonoid(index_set=ZZ, commutative=True)
            Free abelian monoid indexed by Integer Ring
            sage: F = FreeMonoid(index_set=ZZ, names='x,y,z')
            sage: G = FreeMonoid(index_set=ZZ, names=['x', 'y', 'z'])
            sage: F == G
            True
            sage: F is G
            True

            sage: FreeMonoid(2, names='a,b') is FreeMonoid(names=['a','b'])
            True

        Fix a bug when ``index_set`` is ``None`` and ``names`` is a
        string (:trac:`26221`)::

            sage: FreeMonoid(2, names=['a','b']) is FreeMonoid(names='a,b')
            True
        """
        if 'abelian' in kwds:
            commutative = kwds.pop('abelian')

        if commutative:
            from sage.monoids.free_abelian_monoid import FreeAbelianMonoid
            return FreeAbelianMonoid(index_set, names, **kwds)

        # Swap args (this works if names is None as well)
        if isinstance(index_set, str):
            names, index_set = index_set, names

        if index_set is None and names is not None:
            if isinstance(names, str):
                index_set = names.count(',') + 1
            else:
                index_set = len(names)

        if index_set not in ZZ:
            if names is not None:
                names = normalize_names(-1, names)
            from sage.monoids.indexed_free_monoid import IndexedFreeMonoid
            return IndexedFreeMonoid(index_set, names=names, **kwds)

        if names is None:
            raise ValueError("names must be specified")
        names = normalize_names(index_set, names)
        return super(FreeMonoid, cls).__classcall__(cls, index_set, names)
Example #43
0
def FreeMonoid(index_set=None, names=None, commutative=False, **kwds):
    r"""
    Return a free monoid on `n` generators or with the generators indexed by
    a set `I`.

    We construct free monoids by specifing either:

    - the number of generators and/or the names of the generators
    - the indexing set for the generators

    INPUT:

    - ``index_set`` -- an indexing set for the generators; if an integer,
      than this becomes `\{0, 1, \ldots, n-1\}`

    -  ``names`` -- names of generators

    - ``commutative`` -- (default: ``False``) whether the free monoid is
      commutative or not

    OUTPUT:

    A free monoid.

    EXAMPLES::

        sage: F.<a,b,c,d,e> = FreeMonoid(); F
        Free monoid on 5 generators (a, b, c, d, e)
        sage: FreeMonoid(index_set=ZZ)
        Free monoid indexed by Integer Ring

        sage: F.<x,y,z> = FreeMonoid(abelian=True); F
        Free abelian monoid on 3 generators (x, y, z)
        sage: FreeMonoid(index_set=ZZ, commutative=True)
        Free abelian monoid indexed by Integer Ring

    TESTS::

        sage: FreeMonoid(index_set=ZZ, names='x,y,z')
        Free monoid indexed by Integer Ring
    """
    if 'abelian' in kwds:
        commutative = kwds.pop('abelian')

    if commutative:
        from sage.monoids.free_abelian_monoid import FreeAbelianMonoid
        return FreeAbelianMonoid(index_set, names, **kwds)

    if isinstance(index_set, str): # Swap args (this works if names is None as well)
        names, index_set = index_set, names

    if index_set is None and names is not None:
        if isinstance(names, str):
            index_set = names.count(',')
        else:
            index_set = len(names)

    if index_set not in ZZ:
        if names is not None:
            names = normalize_names(-1, names)
        from sage.monoids.indexed_free_monoid import IndexedFreeMonoid
        return IndexedFreeMonoid(index_set, names=names, **kwds)

    if names is None:
        raise ValueError("names must be specified")
    return FreeMonoid_factory(index_set, names)
Example #44
0
    def create_key_and_extra_args(self,
                                  order,
                                  name=None,
                                  modulus=None,
                                  names=None,
                                  impl=None,
                                  proof=None,
                                  check_irreducible=True,
                                  prefix=None,
                                  repr=None,
                                  elem_cache=None,
                                  **kwds):
        """
        EXAMPLES::

            sage: GF.create_key_and_extra_args(9, 'a')
            ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True), {})

        We do not take invalid keyword arguments and raise a value error
        to better ensure uniqueness::

            sage: GF.create_key_and_extra_args(9, 'a', foo='value')
            Traceback (most recent call last):
            ...
            TypeError: create_key_and_extra_args() got an unexpected keyword argument 'foo'

        Moreover, ``repr`` and ``elem_cache`` are ignored when not
        using givaro::

            sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', repr='poly')
            ((16, ('a',), x^4 + x + 1, 'ntl', 2, 4, True, None, None, None), {})
            sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', elem_cache=False)
            ((16, ('a',), x^4 + x + 1, 'ntl', 2, 4, True, None, None, None), {})
            sage: GF(16, impl='ntl') is GF(16, impl='ntl', repr='foo')
            True

        We handle extra arguments for the givaro finite field and
        create unique objects for their defaults::

            sage: GF(25, impl='givaro') is GF(25, impl='givaro', repr='poly')
            True
            sage: GF(25, impl='givaro') is GF(25, impl='givaro', elem_cache=True)
            True
            sage: GF(625, impl='givaro') is GF(625, impl='givaro', elem_cache=False)
            True

        We explicitly take ``structure``, ``implementation`` and ``prec`` attributes
        for compatibility with :class:`~sage.categories.pushout.AlgebraicExtensionFunctor`
        but we ignore them as they are not used, see :trac:`21433`::

            sage: GF.create_key_and_extra_args(9, 'a', structure=None)
            ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True), {})
        """
        import sage.arith.all
        from sage.structure.proof.all import WithProof, arithmetic
        if proof is None:
            proof = arithmetic()
        for key, val in kwds.items():
            if key not in ['structure', 'implementation', 'prec', 'embedding']:
                raise TypeError(
                    "create_key_and_extra_args() got an unexpected keyword argument '%s'"
                    % key)
            if not (val is None
                    or isinstance(val, list) and all(c is None for c in val)):
                raise NotImplementedError(
                    "ring extension with prescribed %s is not implemented" %
                    key)
        with WithProof('arithmetic', proof):
            order = Integer(order)
            if order <= 1:
                raise ValueError(
                    "the order of a finite field must be at least 2")

            if order.is_prime():
                p = order
                n = Integer(1)
                if impl is None:
                    impl = 'modn'
                name = ('x', )  # Ignore name
                # Every polynomial of degree 1 is irreducible
                check_irreducible = False
            elif order.is_prime_power():
                if names is not None:
                    name = names
                if name is not None:
                    name = normalize_names(1, name)

                p, n = order.factor()[0]
                if name is None:
                    if prefix is None:
                        prefix = 'z'
                    name = prefix + str(n)
                    if modulus is not None:
                        raise ValueError(
                            "no modulus may be specified if variable name not given"
                        )
                    # Fpbar will have a strong reference, since algebraic_closure caches its results,
                    # and the coefficients of modulus lie in GF(p)
                    Fpbar = GF(p).algebraic_closure(prefix)
                    # This will give a Conway polynomial if p,n is small enough to be in the database
                    # and a pseudo-Conway polynomial if it's not.
                    modulus = Fpbar._get_polynomial(n)
                    check_irreducible = False

                if impl is None:
                    if order < zech_log_bound:
                        impl = 'givaro'
                    elif p == 2:
                        impl = 'ntl'
                    else:
                        impl = 'pari_ffelt'
            else:
                raise ValueError(
                    "the order of a finite field must be a prime power")

            # Determine modulus.
            # For the 'modn' implementation, we use the following
            # optimization which we also need to avoid an infinite loop:
            # a modulus of None is a shorthand for x-1.
            if modulus is not None or impl != 'modn':
                R = PolynomialRing(FiniteField(p), 'x')
                if modulus is None:
                    modulus = R.irreducible_element(n)
                if isinstance(modulus, str):
                    # A string specifies an algorithm to find a suitable modulus.
                    modulus = R.irreducible_element(n, algorithm=modulus)
                else:
                    if sage.rings.polynomial.polynomial_element.is_Polynomial(
                            modulus):
                        modulus = modulus.change_variable_name('x')
                    modulus = R(modulus).monic()

                    if modulus.degree() != n:
                        raise ValueError(
                            "the degree of the modulus does not equal the degree of the field"
                        )
                    if check_irreducible and not modulus.is_irreducible():
                        raise ValueError(
                            "finite field modulus must be irreducible but it is not"
                        )
                # If modulus is x - 1 for impl="modn", set it to None
                if impl == 'modn' and modulus[0] == -1:
                    modulus = None

            # Check extra arguments for givaro and setup their defaults
            # TODO: ntl takes a repr, but ignores it
            if impl == 'givaro':
                if repr is None:
                    repr = 'poly'
                if elem_cache is None:
                    elem_cache = (order < 500)
            else:
                # This has the effect of ignoring these keywords
                repr = None
                elem_cache = None

            return (order, name, modulus, impl, p, n, proof, prefix, repr,
                    elem_cache), {}
Example #45
0
    def __classcall_private__(cls,
                              k,
                              table,
                              names='e',
                              assume_associative=False,
                              category=None):
        """
        Normalize input.

        TESTS::

            sage: table = [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]
            sage: A1 = FiniteDimensionalAlgebra(GF(3), table)
            sage: A2 = FiniteDimensionalAlgebra(GF(3), table, names='e')
            sage: A3 = FiniteDimensionalAlgebra(GF(3), table, names=['e0', 'e1'])
            sage: A1 is A2 and A2 is A3
            True

        The ``assume_associative`` keyword is built into the category::

            sage: from sage.categories.magmatic_algebras import MagmaticAlgebras
            sage: cat = MagmaticAlgebras(GF(3)).FiniteDimensional().WithBasis()
            sage: A1 = FiniteDimensionalAlgebra(GF(3), table, category=cat.Associative())
            sage: A2 = FiniteDimensionalAlgebra(GF(3), table, assume_associative=True)
            sage: A1 is A2
            True

        Uniqueness depends on the category::

            sage: cat = Algebras(GF(3)).FiniteDimensional().WithBasis()
            sage: A1 = FiniteDimensionalAlgebra(GF(3), table)
            sage: A2 = FiniteDimensionalAlgebra(GF(3), table, category=cat)
            sage: A1 == A2
            False
            sage: A1 is A2
            False

        Checking that equality is still as expected::

            sage: A = FiniteDimensionalAlgebra(GF(3), table)
            sage: B = FiniteDimensionalAlgebra(GF(5), [Matrix([0])])
            sage: A == A
            True
            sage: B == B
            True
            sage: A == B
            False
            sage: A != A
            False
            sage: B != B
            False
            sage: A != B
            True
        """
        n = len(table)
        table = [b.base_extend(k) for b in table]
        for b in table:
            b.set_immutable()
            if not (is_Matrix(b) and b.dimensions() == (n, n)):
                raise ValueError("input is not a multiplication table")
        table = tuple(table)

        cat = MagmaticAlgebras(k).FiniteDimensional().WithBasis()
        cat = cat.or_subcategory(category)
        if assume_associative:
            cat = cat.Associative()

        names = normalize_names(n, names)

        return super(FiniteDimensionalAlgebra, cls).__classcall__(cls,
                                                                  k,
                                                                  table,
                                                                  names,
                                                                  category=cat)
    def __classcall_private__(cls, k, table, names='e', assume_associative=False,
                              category=None):
        """
        Normalize input.

        TESTS::

            sage: table = [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]
            sage: A1 = FiniteDimensionalAlgebra(GF(3), table)
            sage: A2 = FiniteDimensionalAlgebra(GF(3), table, names='e')
            sage: A3 = FiniteDimensionalAlgebra(GF(3), table, names=['e0', 'e1'])
            sage: A1 is A2 and A2 is A3
            True

        The ``assume_associative`` keyword is built into the category::

            sage: from sage.categories.magmatic_algebras import MagmaticAlgebras
            sage: cat = MagmaticAlgebras(GF(3)).FiniteDimensional().WithBasis()
            sage: A1 = FiniteDimensionalAlgebra(GF(3), table, category=cat.Associative())
            sage: A2 = FiniteDimensionalAlgebra(GF(3), table, assume_associative=True)
            sage: A1 is A2
            True

        Uniqueness depends on the category::

            sage: cat = Algebras(GF(3)).FiniteDimensional().WithBasis()
            sage: A1 = FiniteDimensionalAlgebra(GF(3), table)
            sage: A2 = FiniteDimensionalAlgebra(GF(3), table, category=cat)
            sage: A1 == A2
            False
            sage: A1 is A2
            False

        Checking that equality is still as expected::

            sage: A = FiniteDimensionalAlgebra(GF(3), table)
            sage: B = FiniteDimensionalAlgebra(GF(5), [Matrix([0])])
            sage: A == A
            True
            sage: B == B
            True
            sage: A == B
            False
            sage: A != A
            False
            sage: B != B
            False
            sage: A != B
            True
        """
        n = len(table)
        table = [b.base_extend(k) for b in table]
        for b in table:
            b.set_immutable()
            if not (is_Matrix(b) and b.dimensions() == (n, n)):
                raise ValueError("input is not a multiplication table")
        table = tuple(table)

        cat = MagmaticAlgebras(k).FiniteDimensional().WithBasis()
        cat = cat.or_subcategory(category)
        if assume_associative:
            cat = cat.Associative()

        names = normalize_names(n, names)

        return super(FiniteDimensionalAlgebra, cls).__classcall__(cls, k, table,
                             names, category=cat)
Example #47
0
def AffineSpace(n, R=None, names='x', ambient_projective_space=None,
                default_embedding_index=None):
    r"""
    Return affine space of dimension ``n`` over the ring ``R``.

    EXAMPLES:

    The dimension and ring can be given in either order::

        sage: AffineSpace(3, QQ, 'x')
        Affine Space of dimension 3 over Rational Field
        sage: AffineSpace(5, QQ, 'x')
        Affine Space of dimension 5 over Rational Field
        sage: A = AffineSpace(2, QQ, names='XY'); A
        Affine Space of dimension 2 over Rational Field
        sage: A.coordinate_ring()
        Multivariate Polynomial Ring in X, Y over Rational Field

    Use the divide operator for base extension::

        sage: AffineSpace(5, names='x')/GF(17)
        Affine Space of dimension 5 over Finite Field of size 17

    The default base ring is `\ZZ`::

        sage: AffineSpace(5, names='x')
        Affine Space of dimension 5 over Integer Ring

    There is also an affine space associated to each polynomial ring::

        sage: R = GF(7)['x, y, z']
        sage: A = AffineSpace(R); A
        Affine Space of dimension 3 over Finite Field of size 7
        sage: A.coordinate_ring() is R
        True
    """
    if (is_MPolynomialRing(n) or is_PolynomialRing(n)) and R is None:
        R = n
        A = AffineSpace(R.ngens(), R.base_ring(), R.variable_names())
        A._coordinate_ring = R
        return A
    if isinstance(R, integer_types + (Integer,)):
        n, R = R, n
    if R is None:
        R = ZZ  # default is the integers
    if names is None:
        if n == 0:
            names = ''
        else:
            raise TypeError("you must specify the variables names of the coordinate ring")
    names = normalize_names(n, names)
    if default_embedding_index is not None and ambient_projective_space is None:
        from sage.schemes.projective.projective_space import ProjectiveSpace
        ambient_projective_space = ProjectiveSpace(n, R)
    if R in _Fields:
        if is_FiniteField(R):
            return AffineSpace_finite_field(n, R, names,
                                            ambient_projective_space, default_embedding_index)
        else:
            return AffineSpace_field(n, R, names,
                                     ambient_projective_space, default_embedding_index)
    return AffineSpace_generic(n, R, names, ambient_projective_space, default_embedding_index)
Example #48
0
    def create_key(self,
                   base_ring,
                   arg1=None,
                   arg2=None,
                   sparse=False,
                   order='degrevlex',
                   names=None,
                   name=None,
                   implementation=None,
                   degrees=None):
        """
        Create the key under which a free algebra is stored.

        TESTS::

            sage: FreeAlgebra.create_key(GF(5),['x','y','z'])
            (Finite Field of size 5, ('x', 'y', 'z'))
            sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3)
            (Finite Field of size 5, ('x', 'y', 'z'))
            sage: FreeAlgebra.create_key(GF(5),3,'xyz')
            (Finite Field of size 5, ('x', 'y', 'z'))
            sage: FreeAlgebra.create_key(GF(5),['x','y','z'], implementation='letterplace')
            (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
            sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3, implementation='letterplace')
            (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
            sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace')
            (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
            sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace', degrees=[1,2,3])
            ((1, 2, 3), Multivariate Polynomial Ring in x, y, z, x_ over Finite Field of size 5)

        """
        if arg1 is None and arg2 is None and names is None:
            # this is used for pickling
            if degrees is None:
                return (base_ring, )
            return tuple(degrees), base_ring
        PolRing = None
        # test if we can use libSingular/letterplace
        if implementation is not None and implementation != 'generic':
            try:
                PolRing = PolynomialRing(
                    base_ring,
                    arg1,
                    arg2,
                    sparse=sparse,
                    order=order,
                    names=names,
                    name=name,
                    implementation=implementation
                    if implementation != 'letterplace' else None)
                if not isinstance(PolRing, MPolynomialRing_libsingular):
                    if PolRing.ngens() == 1:
                        PolRing = PolynomialRing(base_ring, 1,
                                                 PolRing.variable_names())
                        if not isinstance(PolRing,
                                          MPolynomialRing_libsingular):
                            raise TypeError
                    else:
                        raise TypeError
            except (TypeError, NotImplementedError) as msg:
                raise NotImplementedError(
                    "The letterplace implementation is not available for the free algebra you requested"
                )
        if PolRing is not None:
            if degrees is None:
                return (PolRing, )
            from sage.all import TermOrder
            T = PolRing.term_order() + TermOrder('lex', 1)
            varnames = list(PolRing.variable_names())
            newname = 'x'
            while newname in varnames:
                newname += '_'
            varnames.append(newname)
            return tuple(degrees), PolynomialRing(
                PolRing.base(),
                varnames,
                sparse=sparse,
                order=T,
                implementation=implementation
                if implementation != 'letterplace' else None)
        # normalise the generator names
        from sage.all import Integer
        if isinstance(arg1, (Integer, ) + integer_types):
            arg1, arg2 = arg2, arg1
        if not names is None:
            arg1 = names
        elif not name is None:
            arg1 = name
        if arg2 is None:
            arg2 = len(arg1)
        names = normalize_names(arg2, arg1)
        return base_ring, names
Example #49
0
def FreeGroup(n=None, names='x', index_set=None, abelian=False, **kwds):
    """
    Construct a Free Group.

    INPUT:

    - ``n`` -- integer or ``None`` (default). The number of
      generators. If not specified the ``names`` are counted.
    - ``names`` -- string or list/tuple/iterable of strings (default:
      ``'x'``). The generator names or name prefix.
    - ``index_set`` -- (optional) an index set for the generators; if
      specified then the optional keyword ``abelian`` can be used
    - ``abelian`` -- (default: ``False``) whether to construct a free
      abelian group or a free group

    .. NOTE::

        If you want to create a free group, it is currently preferential to
        use ``Groups().free(...)`` as that does not load GAP.

    EXAMPLES::

        sage: from train_track import *
        sage: G.<a,b> = FreeGroup();  G
        Free Group on generators {a, b}
        sage: H = FreeGroup('a, b')
        sage: G is H
        True
        sage: FreeGroup(0)
        Free Group on generators {}

    The entry can be either a string with the names of the generators,
    or the number of generators and the prefix of the names to be
    given. The default prefix is ``'x'`` ::

        sage: FreeGroup(3)
        Free Group on generators {x0, x1, x2}
        sage: FreeGroup(3, 'g')
        Free Group on generators {g0, g1, g2}
        sage: FreeGroup()
        Free Group on generators {x}

    We give two examples using the ``index_set`` option::

        sage: FreeGroup(index_set=ZZ)
        Free group indexed by Integer Ring
        sage: FreeGroup(index_set=ZZ, abelian=True)
        Free abelian group indexed by Integer Ring

    TESTS::

        sage: G1 = FreeGroup(2, 'a,b')
        sage: G2 = FreeGroup('a,b')
        sage: G3.<a,b> = FreeGroup()
        sage: G1 is G2, G2 is G3
        (True, True)
    """
    # Support Freegroup('a,b') syntax
    if n is not None:
        try:
            n = Integer(n)
        except TypeError:
            names = n
            n = None
    # derive n from counting names
    if n is None:
        if isinstance(names, six.string_types):
            n = len(names.split(','))
        else:
            names = list(names)
            n = len(names)
    from sage.structure.category_object import normalize_names
    names = normalize_names(n, names)
    if index_set is not None or abelian:
        if abelian:
            from sage.groups.indexed_free_group import IndexedFreeAbelianGroup
            return IndexedFreeAbelianGroup(index_set, names=names, **kwds)

        from sage.groups.indexed_free_group import IndexedFreeGroup
        return IndexedFreeGroup(index_set, names=names, **kwds)
    from train_track.free_group import FreeGroup_class
    return FreeGroup_class(names)
Example #50
0
def BooleanPolynomialRing_constructor(n=None, names=None, order="lex"):
    """
    Construct a boolean polynomial ring with the following
    parameters:

    INPUT:

    - ``n`` -- number of variables (an integer > 1)
    - ``names`` -- names of ring variables, may be a string or list/tuple of strings
    - ``order`` -- term order (default: lex)

    EXAMPLES::

        sage: R.<x, y, z> = BooleanPolynomialRing() # indirect doctest
        sage: R
        Boolean PolynomialRing in x, y, z

        sage: p = x*y + x*z + y*z
        sage: x*p
        x*y*z + x*y + x*z

        sage: R.term_order()
        Lexicographic term order

        sage: R = BooleanPolynomialRing(5,'x',order='deglex(3),deglex(2)')
        sage: R.term_order()
        Block term order with blocks:
        (Degree lexicographic term order of length 3,
         Degree lexicographic term order of length 2)

        sage: R = BooleanPolynomialRing(3,'x',order='degneglex')
        sage: R.term_order()
        Degree negative lexicographic term order

        sage: BooleanPolynomialRing(names=('x','y'))
        Boolean PolynomialRing in x, y

        sage: BooleanPolynomialRing(names='x,y')
        Boolean PolynomialRing in x, y

    TESTS::

        sage: P.<x,y> = BooleanPolynomialRing(2,order='deglex')
        sage: x > y
        True

        sage: P.<x0, x1, x2, x3> = BooleanPolynomialRing(4,order='deglex(2),deglex(2)')
        sage: x0 > x1
        True
        sage: x2 > x3
        True
    """

    if isinstance(n, str):
        names = n
        n = -1
    elif n is None:
        n = -1

    names = normalize_names(n, names)
    n = len(names)

    from sage.rings.polynomial.term_order import TermOrder

    order = TermOrder(order, n)

    key = ("pbori", names, n, order)
    R = _get_from_cache(key)
    if not R is None:
        return R

    from sage.rings.polynomial.pbori import BooleanPolynomialRing
    R = BooleanPolynomialRing(n, names, order)

    _save_in_cache(key, R)
    return R
    def __classcall_private__(cls,
                              base_ring,
                              twist=None,
                              names=None,
                              sparse=False):
        r"""
        Construct the Ore polynomial ring associated to the given parameters.

        TESTS::

            sage: R.<t> = QQ[]
            sage: der = R.derivation()
            sage: A.<d> = OrePolynomialRing(R, der)
            sage: A
            Ore Polynomial Ring in d over Univariate Polynomial Ring in t over Rational Field twisted by d/dt
            sage: type(A)
            <class 'sage.rings.polynomial.ore_polynomial_ring.OrePolynomialRing_with_category'>

        We check the uniqueness property of parents::

            sage: der2 = R.derivation()
            sage: B.<d> = OrePolynomialRing(R, der2)
            sage: A is B
            True

        When there is no twisting derivation, a special class is used::

            sage: k.<t> = ZZ[]
            sage: theta = k.hom([t+1])
            sage: S.<x> = OrePolynomialRing(k, theta)
            sage: S
            Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1
            sage: type(S)
            <class 'sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_with_category'>

        In certain situations (e.g. when the twisting morphism is the Frobenius
        over a finite field), even more specialized classes are used::

            sage: k.<a> = GF(7^5)
            sage: Frob = k.frobenius_endomorphism(2)
            sage: S.<x> = SkewPolynomialRing(k, Frob)
            sage: type(S)
            <class 'sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_finite_field_with_category'>
        """
        if base_ring not in CommutativeRings():
            raise TypeError('base_ring must be a commutative ring')
        if isinstance(twist, Morphism):
            if (twist.domain() is not base_ring
                    or twist.codomain() is not base_ring):
                raise TypeError(
                    "the twisting morphism must be an endomorphism of base_ring (=%s)"
                    % base_ring)
            if twist.is_identity():
                morphism = None
            else:
                morphism = twist
            derivation = None
        elif isinstance(twist, RingDerivation):
            if (twist.domain() is not base_ring
                    or twist.codomain() is not base_ring):
                raise TypeError(
                    "the twisting derivation must be an endomorphism of base_ring (=%s)"
                    % base_ring)
            morphism = twist.parent().twisting_morphism()
            if twist:
                derivation = twist
            else:
                derivation = None
        else:
            raise TypeError(
                "the twisting map must be a ring morphism or a derivation")
        if names is None:
            raise TypeError("you must specify the name of the variable")
        try:
            names = normalize_names(1, names)[0]
        except IndexError:
            raise NotImplementedError(
                "multivariate Ore polynomials rings not supported")

        # If there is no twisting morphism and no twisting derivation
        # we return a classical polynomial ring
        if derivation is None and morphism is None:
            return PolynomialRing(base_ring, names, sparse=sparse)

        # We find the best constructor
        if sparse:
            raise NotImplementedError(
                "sparse Ore polynomial rings are not implemented")

        from sage.rings.polynomial import skew_polynomial_ring
        constructors = []
        if derivation is None:
            if base_ring in _Fields:
                try:
                    order = morphism.order()
                    if order is not Infinity:
                        if base_ring.is_finite():
                            constructors.append(
                                skew_polynomial_ring.
                                SkewPolynomialRing_finite_field)
                        else:
                            constructors.append(
                                skew_polynomial_ring.
                                SkewPolynomialRing_finite_order)
                except (AttributeError, NotImplementedError):
                    pass
            constructors.append(skew_polynomial_ring.SkewPolynomialRing)

        for constructor in constructors:
            try:
                return constructor(base_ring, morphism, derivation, names,
                                   sparse)
            except (AttributeError, NotImplementedError):
                pass

        # We fallback to generic implementation
        return cls.__classcall__(cls, base_ring, morphism, derivation, names,
                                 sparse)