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
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
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)
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()
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
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
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)
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)
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
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
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)
def create_key(self, n, names): n = int(n) names = normalize_names(n, names) return (n, names)
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
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)
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)
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)
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
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), {}
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)
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)
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
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
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)
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
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
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
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
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
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
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
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)
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), {}
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 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)
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
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)
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)