Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
"""Implementation of :class:`PolynomialRing` class. """
CoercionFailed, ExactQuotientFailed, NotReversible)
# XXX why does this derive from CharacteristicZero???
""" Base class for generalized polynomial rings.
This base class should be used for uniform access to generalized polynomial rings. Subclasses only supply information about the element storage etc.
Do not instantiate. """
if not gens: raise GeneratorsNeeded("generators not specified")
lev = len(gens) - 1 self.ngens = len(gens)
self.zero = self.dtype.zero(lev, dom, ring=self) self.one = self.dtype.one(lev, dom, ring=self)
self.domain = self.dom = dom self.symbols = self.gens = gens # NOTE 'order' may not be set if inject was called through CompositeDomain self.order = opts.get('order', monomial_key(self.default_order))
return self.dtype(element, self.dom, len(self.gens) - 1, ring=self)
s_order = str(self.order) orderstr = ( " order=" + s_order) if s_order != self.default_order else "" return str(self.dom) + '[' + ','.join(map(str, self.gens)) + orderstr + ']'
return hash((self.__class__.__name__, self.dtype, self.dom, self.gens, self.order))
"""Returns `True` if two domains are equivalent. """ return isinstance(other, PolynomialRingBase) and \ self.dtype == other.dtype and self.dom == other.dom and \ self.gens == other.gens and self.order == other.order
"""Convert a Python `int` object to `dtype`. """ return K1(K1.dom.convert(a, K0))
"""Convert a Python `Fraction` object to `dtype`. """ return K1(K1.dom.convert(a, K0))
"""Convert a GMPY `mpz` object to `dtype`. """ return K1(K1.dom.convert(a, K0))
"""Convert a GMPY `mpq` object to `dtype`. """ return K1(K1.dom.convert(a, K0))
"""Convert a mpmath `mpf` object to `dtype`. """ return K1(K1.dom.convert(a, K0))
"""Convert a `ANP` object to `dtype`. """ if K1.dom == K0: return K1(a)
"""Convert a `DMP` object to `dtype`. """ if K1.gens == K0.gens: if K1.dom == K0.dom: return K1(a.rep) # set the correct ring else: return K1(a.convert(K1.dom).rep) else: monoms, coeffs = _dict_reorder(a.to_dict(), K0.gens, K1.gens)
if K1.dom != K0.dom: coeffs = [ K1.dom.convert(c, K0.dom) for c in coeffs ]
return K1(dict(zip(monoms, coeffs)))
"""Returns a field associated with `self`. """ return FractionField(self.dom, *self.gens)
"""Returns a polynomial ring, i.e. `K[X]`. """ raise NotImplementedError('nested domains not allowed')
"""Returns a fraction field, i.e. `K(X)`. """ raise NotImplementedError('nested domains not allowed')
try: return 1/a except (ExactQuotientFailed, ZeroDivisionError): raise NotReversible('%s is not a unit' % a)
"""Extended GCD of `a` and `b`. """ return a.gcdex(b)
"""Returns GCD of `a` and `b`. """ return a.gcd(b)
"""Returns LCM of `a` and `b`. """ return a.lcm(b)
"""Returns factorial of `a`. """ return self.dtype(self.dom.factorial(a))
""" For internal use by the modules class.
Convert an iterable of elements of this ring into a sparse distributed module element. """ raise NotImplementedError
"""Helper for _sdm_to_vector.""" from sympy.polys.distributedmodules import sdm_to_dict dic = sdm_to_dict(s) res = [{} for _ in range(n)] for k, v in dic.items(): res[k[0]][k[1:]] = v return res
""" For internal use by the modules class.
Convert a sparse distributed module into a list of length ``n``.
>>> from sympy import QQ, ilex >>> from sympy.abc import x, y >>> R = QQ.old_poly_ring(x, y, order=ilex) >>> L = [((1, 1, 1), QQ(1)), ((0, 1, 0), QQ(1)), ((0, 0, 1), QQ(2))] >>> R._sdm_to_vector(L, 2) [x + 2*y, x*y] """ dics = self._sdm_to_dics(s, n) # NOTE this works for global and local rings! return [self(x) for x in dics]
""" Generate a free module of rank ``rank`` over ``self``.
>>> from sympy.abc import x >>> from sympy import QQ >>> QQ.old_poly_ring(x).free_module(2) QQ[x]**2 """ return FreeModulePolyRing(self, rank)
"""Helper method for common code in Global and Local poly rings.""" from sympy.polys.distributedmodules import sdm_from_dict d = {} for i, e in enumerate(v): for key, value in e.to_dict().items(): d[(i,) + key] = value return sdm_from_dict(d, order)
"""A true polynomial ring, with objects DMP. """
""" Convert a ``DMF`` object to ``DMP``.
Examples ========
>>> from sympy.polys.polyclasses import DMP, DMF >>> from sympy.polys.domains import ZZ >>> from sympy.abc import x
>>> f = DMF(([ZZ(1), ZZ(1)], [ZZ(1)]), ZZ) >>> K = ZZ.old_frac_field(x)
>>> F = ZZ.old_poly_ring(x).from_FractionField(f, K)
>>> F == DMP([ZZ(1), ZZ(1)], ZZ) True >>> type(F) <class 'sympy.polys.polyclasses.DMP'>
""" if a.denom().is_one: return K1.from_GlobalPolynomialRing(a.numer(), K0)
"""Convert `a` to a SymPy object. """ return basic_from_dict(a.to_sympy_dict(), *self.gens)
"""Convert SymPy's expression to `dtype`. """ try: rep, _ = dict_from_basic(a, gens=self.gens) except PolynomialError: raise CoercionFailed("can't convert %s to type %s" % (a, self))
for k, v in rep.items(): rep[k] = self.dom.from_sympy(v)
return self(rep)
"""Returns True if `LC(a)` is positive. """ return self.dom.is_positive(a.LC())
"""Returns True if `LC(a)` is negative. """ return self.dom.is_negative(a.LC())
"""Returns True if `LC(a)` is non-positive. """ return self.dom.is_nonpositive(a.LC())
"""Returns True if `LC(a)` is non-negative. """ return self.dom.is_nonnegative(a.LC())
""" >>> from sympy import lex, QQ >>> from sympy.abc import x, y >>> R = QQ.old_poly_ring(x, y) >>> f = R.convert(x + 2*y) >>> g = R.convert(x * y) >>> R._vector_to_sdm([f, g], lex) [((1, 1, 1), 1), ((0, 1, 0), 1), ((0, 0, 1), 2)] """ return _vector_to_sdm_helper(v, order)
"""A generalized polynomial ring, with objects DMF. """
"""Construct an element of `self` domain from `a`. """ res = self.dtype(a, self.dom, len(self.gens) - 1, ring=self)
# make sure res is actually in our ring if res.denom().terms(order=self.order)[0][0] != (0,)*len(self.gens): from sympy.printing.str import sstr raise CoercionFailed("denominator %s not allowed in %s" % (sstr(res), self)) return res
try: a = self.convert(a) except CoercionFailed: return False return a.denom().terms(order=self.order)[0][0] == (0,)*len(self.gens)
dmf = K1.get_field().from_FractionField(a, K0) return K1((dmf.num, dmf.den))
"""Convert `a` to a SymPy object. """ return (basic_from_dict(a.numer().to_sympy_dict(), *self.gens) / basic_from_dict(a.denom().to_sympy_dict(), *self.gens))
"""Convert SymPy's expression to `dtype`. """ p, q = a.as_numer_denom()
num, _ = dict_from_basic(p, gens=self.gens) den, _ = dict_from_basic(q, gens=self.gens)
for k, v in num.items(): num[k] = self.dom.from_sympy(v)
for k, v in den.items(): den[k] = self.dom.from_sympy(v)
return self((num, den)).cancel()
""" Turn an iterable into a sparse distributed module.
Note that the vector is multiplied by a unit first to make all entries polynomials.
>>> from sympy import ilex, QQ >>> from sympy.abc import x, y >>> R = QQ.old_poly_ring(x, y, order=ilex) >>> f = R.convert((x + 2*y) / (1 + x)) >>> g = R.convert(x * y) >>> R._vector_to_sdm([f, g], ilex) [((0, 0, 1), 2), ((0, 1, 0), 1), ((1, 1, 1), 1), ((1, 2, 1), 1)] """ # NOTE this is quite inefficient... u = self.one.numer() for x in v: u *= x.denom() return _vector_to_sdm_helper([x.numer()*u/x.denom() for x in v], order)
def PolynomialRing(dom, *gens, **opts): r""" Create a generalized multivariate polynomial ring.
A generalized polynomial ring is defined by a ground field `K`, a set of generators (typically `x_1, \dots, x_n`) and a monomial order `<`. The monomial order can be global, local or mixed. In any case it induces a total ordering on the monomials, and there exists for every (non-zero) polynomial `f \in K[x_1, \dots, x_n]` a well-defined "leading monomial" `LM(f) = LM(f, >)`. One can then define a multiplicative subset `S = S_> = \{f \in K[x_1, \dots, x_n] | LM(f) = 1\}`. The generalized polynomial ring corresponding to the monomial order is `R = S^{-1}K[x_1, \dots, x_n]`.
If `>` is a so-called global order, that is `1` is the smallest monomial, then we just have `S = K` and `R = K[x_1, \dots, x_n]`.
Examples ========
A few examples may make this clearer.
>>> from sympy.abc import x, y >>> from sympy import QQ
Our first ring uses global lexicographic order.
>>> R1 = QQ.old_poly_ring(x, y, order=(("lex", x, y),))
The second ring uses local lexicographic order. Note that when using a single (non-product) order, you can just specify the name and omit the variables:
>>> R2 = QQ.old_poly_ring(x, y, order="ilex")
The third and fourth rings use a mixed orders:
>>> o1 = (("ilex", x), ("lex", y)) >>> o2 = (("lex", x), ("ilex", y)) >>> R3 = QQ.old_poly_ring(x, y, order=o1) >>> R4 = QQ.old_poly_ring(x, y, order=o2)
We will investigate what elements of `K(x, y)` are contained in the various rings.
>>> L = [x, 1/x, y/(1 + x), 1/(1 + y), 1/(1 + x*y)] >>> test = lambda R: [f in R for f in L]
The first ring is just `K[x, y]`:
>>> test(R1) [True, False, False, False, False]
The second ring is R1 localised at the maximal ideal (x, y):
>>> test(R2) [True, False, True, True, True]
The third ring is R1 localised at the prime ideal (x):
>>> test(R3) [True, False, True, False, True]
Finally the fourth ring is R1 localised at `S = K[x, y] \setminus yK[y]`:
>>> test(R4) [True, False, False, True, False] """
order = opts.get("order", GeneralizedPolynomialRing.default_order) if iterable(order): order = build_product_order(order, gens) order = monomial_key(order) opts['order'] = order
if order.is_global: return GlobalPolynomialRing(dom, *gens, **opts) else: return GeneralizedPolynomialRing(dom, *gens, **opts) |