def ideal(self, *gens, **kwds): """ Create an ideal in this polynomial ring. """ do_coerce = False if len(gens) == 1: from sage.rings.ideal import is_Ideal if is_Ideal(gens[0]): if gens[0].ring() is self: return gens[0] gens = gens[0].gens() elif isinstance(gens[0], (list, tuple)): gens = gens[0] if not self._has_singular: # pass through MPolynomialRing_generic.ideal(self,gens,**kwds) if is_SingularElement(gens): gens = list(gens) do_coerce = True if is_Macaulay2Element(gens): gens = list(gens) do_coerce = True elif not isinstance(gens, (list, tuple)): gens = [gens] if ('coerce' in kwds and kwds['coerce']) or do_coerce: gens = [self(x) for x in gens] # this will even coerce from singular ideals correctly! return multi_polynomial_ideal.MPolynomialIdeal(self, gens, **kwds)
def ideal(self, *gens, **kwds): """ Create an ideal in this polynomial ring. """ do_coerce = False if len(gens) == 1: from sage.rings.ideal import is_Ideal if is_Ideal(gens[0]): if gens[0].ring() is self: return gens[0] gens = gens[0].gens() elif isinstance(gens[0], (list, tuple)): gens = gens[0] if not self._has_singular: # pass through MPolynomialRing_generic.ideal(self, gens, **kwds) if is_SingularElement(gens): gens = list(gens) do_coerce = True if is_Macaulay2Element(gens): gens = list(gens) do_coerce = True elif not isinstance(gens, (list, tuple)): gens = [gens] if ('coerce' in kwds and kwds['coerce']) or do_coerce: gens = [self(x) for x in gens ] # this will even coerce from singular ideals correctly! return multi_polynomial_ideal.MPolynomialIdeal(self, gens, **kwds)
def __call__(self, x, check=True): """ Convert ``x`` to an element of this multivariate polynomial ring, possibly non-canonically. EXAMPLES: We create a Macaulay2 multivariate polynomial via ideal arithmetic, then convert it into R. :: sage: R.<x,y> = PolynomialRing(QQ, 2) # optional sage: I = R.ideal([x^3 + y, y]) # optional sage: S = I._macaulay2_() # optional sage: T = S*S*S # optional sage: U = T.gens().entries().flatten() # optional sage: f = U[2]; f # optional x^6*y+2*x^3*y^2+y^3 sage: R(repr(f)) # optional x^6*y + 2*x^3*y^2 + y^3 Some other subtle conversions. We create polynomial rings in 2 variables over the rationals, integers, and a finite field. :: sage: R.<x,y> = QQ[] sage: S.<x,y> = ZZ[] sage: T.<x,y> = GF(7)[] We convert from integer polynomials to rational polynomials, and back:: sage: f = R(S.0^2 - 4*S.1^3); f -4*y^3 + x^2 sage: parent(f) Multivariate Polynomial Ring in x, y over Rational Field sage: parent(S(f)) Multivariate Polynomial Ring in x, y over Integer Ring We convert from polynomials over the finite field. :: sage: f = R(T.0^2 - 4*T.1^3); f 3*y^3 + x^2 sage: parent(f) Multivariate Polynomial Ring in x, y over Rational Field We dump and load the polynomial ring S:: sage: S2 = loads(dumps(S)) sage: S2 == S True Coerce works and gets the right parent. :: sage: parent(S2._coerce_(S.0)) is S2 True Conversion to reduce modulo a prime between rings with different variable names:: sage: R.<x,y> = PolynomialRing(QQ,2) sage: S.<a,b> = PolynomialRing(GF(7),2) sage: f = x^2 + 2/3*y^3 sage: S(f) 3*b^3 + a^2 Conversion from symbolic variables:: sage: x,y,z = var('x,y,z') sage: R = QQ[x,y,z] sage: type(x) <type 'sage.symbolic.expression.Expression'> sage: type(R(x)) <type 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'> sage: f = R(x^3 + y^3 - z^3); f x^3 + y^3 - z^3 sage: type(f) <type 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'> sage: parent(f) Multivariate Polynomial Ring in x, y, z over Rational Field A more complicated symbolic and computational mix. Behind the scenes Singular and Maxima are doing the real work. :: sage: R = QQ[x,y,z] sage: f = (x^3 + y^3 - z^3)^10; f (x^3 + y^3 - z^3)^10 sage: g = R(f); parent(g) Multivariate Polynomial Ring in x, y, z over Rational Field sage: (f - g).expand() 0 It intelligently handles conversions from polynomial rings in a subset of the variables too. :: sage: R = GF(5)['x,y,z'] sage: S = ZZ['y'] sage: R(7*S.0) 2*y sage: T = ZZ['x,z'] sage: R(2*T.0 + 6*T.1 + T.0*T.1^2) x*z^2 + 2*x + z :: sage: R = QQ['t,x,y,z'] sage: S.<x> = ZZ['x'] sage: T.<z> = S['z'] sage: T Univariate Polynomial Ring in z over Univariate Polynomial Ring in x over Integer Ring sage: f = (x+3*z+5)^2; f 9*z^2 + (6*x + 30)*z + x^2 + 10*x + 25 sage: R(f) x^2 + 6*x*z + 9*z^2 + 10*x + 30*z + 25 Arithmetic with a constant from a base ring:: sage: R.<u,v> = QQ[] sage: S.<x,y> = R[] sage: u^3*x^2 + v*y u^3*x^2 + v*y Stacked polynomial rings convert into constants if possible. First, the univariate case:: sage: R.<x> = QQ[] sage: S.<u,v> = R[] sage: S(u + 2) u + 2 sage: S(u + 2).degree() 1 sage: S(x + 3) x + 3 sage: S(x + 3).degree() 0 Second, the multivariate case:: sage: R.<x,y> = QQ[] sage: S.<u,v> = R[] sage: S(x + 2*y) x + 2*y sage: S(u + 2*v) u + 2*v Conversion from strings:: sage: R.<x,y> = QQ[] sage: R('x+(1/2)*y^2') 1/2*y^2 + x sage: S.<u,v> = ZZ[] sage: S('u^2 + u*v + v^2') u^2 + u*v + v^2 Foreign polynomial rings convert into the highest ring; the point here is that an element of T could convert to an element of R or an element of S; it is anticipated that an element of T is more likely to be "the right thing" and is historically consistent. :: sage: R.<x,y> = QQ[] sage: S.<u,v> = R[] sage: T.<a,b> = QQ[] sage: S(a + b) u + v TESTS: Check if we still allow nonsense :trac:`7951`:: sage: P = PolynomialRing(QQ, 0, '') sage: P('pi') Traceback (most recent call last): ... TypeError: Unable to coerce pi (<class 'sage.symbolic.constants.Pi'>) to Rational Check that it is possible to convert strings to iterated polynomial rings :trac:`13327`:: sage: Rm = QQ["a"]["b, c"] sage: Rm("a*b") a*b sage: parent(_) is Rm True """ from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict import sage.rings.polynomial.polynomial_element as polynomial_element # handle constants that coerce into self.base_ring() first, if possible if isinstance(x, Element) and x.parent() is self.base_ring(): # A Constant multi-polynomial return self({self._zero_tuple:x}) try: y = self.base_ring()._coerce_(x) return MPolynomial_polydict(self, {self._zero_tuple:y}) except TypeError: pass from multi_polynomial_libsingular import MPolynomial_libsingular if isinstance(x, MPolynomial_polydict): P = x.parent() if P is self: return x elif P == self: return MPolynomial_polydict(self, x.element().dict()) elif self.base_ring().has_coerce_map_from(P): # it might be in the base ring (i.e. a poly ring over a poly ring) c = self.base_ring()(x) return MPolynomial_polydict(self, {self._zero_tuple:c}) elif len(P.variable_names()) == len(self.variable_names()): # Map the variables in some crazy way (but in order, # of course). This is here since R(blah) is supposed # to be "make an element of R if at all possible with # no guarantees that this is mathematically solid." K = self.base_ring() D = x.element().dict() for i, a in D.iteritems(): D[i] = K(a) return MPolynomial_polydict(self, D) elif set(P.variable_names()).issubset(set(self.variable_names())) and self.base_ring().has_coerce_map_from(P.base_ring()): # If the named variables are a superset of the input, map the variables by name return MPolynomial_polydict(self, self._extract_polydict(x)) else: return MPolynomial_polydict(self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) elif isinstance(x, MPolynomial_libsingular): P = x.parent() if P == self: return MPolynomial_polydict(self, x.dict()) elif self.base_ring().has_coerce_map_from(P): # it might be in the base ring (i.e. a poly ring over a poly ring) c = self.base_ring()(x) return MPolynomial_polydict(self, {self._zero_tuple:c}) elif len(P.variable_names()) == len(self.variable_names()): # Map the variables in some crazy way (but in order, # of course). This is here since R(blah) is supposed # to be "make an element of R if at all possible with # no guarantees that this is mathematically solid." K = self.base_ring() D = x.dict() for i, a in D.iteritems(): D[i] = K(a) return MPolynomial_polydict(self, D) elif set(P.variable_names()).issubset(set(self.variable_names())) and self.base_ring().has_coerce_map_from(P.base_ring()): # If the named variables are a superset of the input, map the variables by name return MPolynomial_polydict(self, self._extract_polydict(x)) else: return MPolynomial_polydict(self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) elif isinstance(x, polynomial_element.Polynomial): return MPolynomial_polydict(self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) elif isinstance(x, PolyDict): return MPolynomial_polydict(self, x) elif isinstance(x, fraction_field_element.FractionFieldElement) and x.parent().ring() == self: if x.denominator() == 1: return x.numerator() else: raise TypeError("unable to coerce since the denominator is not 1") elif is_SingularElement(x) and self._has_singular: self._singular_().set_ring() try: return x.sage_poly(self) except TypeError: raise TypeError("unable to coerce singular object") elif hasattr(x, '_polynomial_'): return x._polynomial_(self) elif isinstance(x, str): try: from sage.misc.sage_eval import sage_eval return self(sage_eval(x, self.gens_dict_recursive())) except NameError as e: raise TypeError("unable to convert string") elif is_Macaulay2Element(x): try: s = x.sage_polystring() if len(s) == 0: raise TypeError # NOTE: It's CRUCIAL to use the eval command as follows, # i.e., with the gen dict as the third arg and the second # empty. Otherwise pickling won't work after calls to this eval!!! # This took a while to figure out! return self(eval(s, {}, self.gens_dict())) except (AttributeError, TypeError, NameError, SyntaxError): raise TypeError("Unable to coerce macaulay2 object") return MPolynomial_polydict(self, x) if isinstance(x, dict): return MPolynomial_polydict(self, x) else: c = self.base_ring()(x) return MPolynomial_polydict(self, {self._zero_tuple:c})
def __call__(self, x, check=True): """ Convert ``x`` to an element of this multivariate polynomial ring, possibly non-canonically. EXAMPLES: We create a Macaulay2 multivariate polynomial via ideal arithmetic, then convert it into R. :: sage: R.<x,y> = PolynomialRing(QQ, 2) sage: I = R.ideal([x^3 + y, y]) sage: S = I._macaulay2_() # optional - macaulay2 sage: T = S*S*S # optional - macaulay2 sage: U = T.gens().entries().flatten() # optional - macaulay2 sage: f = U[2]; f # optional - macaulay2 x^6*y+2*x^3*y^2+y^3 sage: R(repr(f)) # optional - macaulay2 x^6*y + 2*x^3*y^2 + y^3 Some other subtle conversions. We create polynomial rings in 2 variables over the rationals, integers, and a finite field. :: sage: R.<x,y> = QQ[] sage: S.<x,y> = ZZ[] sage: T.<x,y> = GF(7)[] We convert from integer polynomials to rational polynomials, and back:: sage: f = R(S.0^2 - 4*S.1^3); f -4*y^3 + x^2 sage: parent(f) Multivariate Polynomial Ring in x, y over Rational Field sage: parent(S(f)) Multivariate Polynomial Ring in x, y over Integer Ring We convert from polynomials over the finite field. :: sage: f = R(T.0^2 - 4*T.1^3); f 3*y^3 + x^2 sage: parent(f) Multivariate Polynomial Ring in x, y over Rational Field We dump and load the polynomial ring S:: sage: S2 = loads(dumps(S)) sage: S2 == S True Coerce works and gets the right parent. :: sage: parent(S2._coerce_(S.0)) is S2 True Conversion to reduce modulo a prime between rings with different variable names:: sage: R.<x,y> = PolynomialRing(QQ,2) sage: S.<a,b> = PolynomialRing(GF(7),2) sage: f = x^2 + 2/3*y^3 sage: S(f) 3*b^3 + a^2 Conversion from symbolic variables:: sage: x,y,z = var('x,y,z') sage: R = QQ['x,y,z'] sage: type(x) <type 'sage.symbolic.expression.Expression'> sage: type(R(x)) <type 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'> sage: f = R(x^3 + y^3 - z^3); f x^3 + y^3 - z^3 sage: type(f) <type 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'> sage: parent(f) Multivariate Polynomial Ring in x, y, z over Rational Field A more complicated symbolic and computational mix. Behind the scenes Singular and Maxima are doing the real work. :: sage: R = QQ['x,y,z'] sage: f = (x^3 + y^3 - z^3)^10; f (x^3 + y^3 - z^3)^10 sage: g = R(f); parent(g) Multivariate Polynomial Ring in x, y, z over Rational Field sage: (f - g).expand() 0 It intelligently handles conversions from polynomial rings in a subset of the variables too. :: sage: R = GF(5)['x,y,z'] sage: S = ZZ['y'] sage: R(7*S.0) 2*y sage: T = ZZ['x,z'] sage: R(2*T.0 + 6*T.1 + T.0*T.1^2) x*z^2 + 2*x + z :: sage: R = QQ['t,x,y,z'] sage: S.<x> = ZZ['x'] sage: T.<z> = S['z'] sage: T Univariate Polynomial Ring in z over Univariate Polynomial Ring in x over Integer Ring sage: f = (x+3*z+5)^2; f 9*z^2 + (6*x + 30)*z + x^2 + 10*x + 25 sage: R(f) x^2 + 6*x*z + 9*z^2 + 10*x + 30*z + 25 Arithmetic with a constant from a base ring:: sage: R.<u,v> = QQ[] sage: S.<x,y> = R[] sage: u^3*x^2 + v*y u^3*x^2 + v*y Stacked polynomial rings convert into constants if possible. First, the univariate case:: sage: R.<x> = QQ[] sage: S.<u,v> = R[] sage: S(u + 2) u + 2 sage: S(u + 2).degree() 1 sage: S(x + 3) x + 3 sage: S(x + 3).degree() 0 Second, the multivariate case:: sage: R.<x,y> = QQ[] sage: S.<u,v> = R[] sage: S(x + 2*y) x + 2*y sage: S(u + 2*v) u + 2*v Conversion from strings:: sage: R.<x,y> = QQ[] sage: R('x+(1/2)*y^2') 1/2*y^2 + x sage: S.<u,v> = ZZ[] sage: S('u^2 + u*v + v^2') u^2 + u*v + v^2 Foreign polynomial rings convert into the highest ring; the point here is that an element of T could convert to an element of R or an element of S; it is anticipated that an element of T is more likely to be "the right thing" and is historically consistent. :: sage: R.<x,y> = QQ[] sage: S.<u,v> = R[] sage: T.<a,b> = QQ[] sage: S(a + b) u + v TESTS: Check if we still allow nonsense (see :trac:`7951`):: sage: P = PolynomialRing(QQ, 0, '') sage: P('pi') Traceback (most recent call last): ... TypeError: Unable to coerce pi (<class 'sage.symbolic.constants.Pi'>) to Rational Check that it is possible to convert strings to iterated polynomial rings (see :trac:`13327`):: sage: Rm = QQ["a"]["b, c"] sage: Rm("a*b") a*b sage: parent(_) is Rm True Check that conversion from PARI works correctly (see :trac:`17974`):: sage: A.<a> = PolynomialRing(QQ) sage: B.<d,e> = PolynomialRing(A) sage: f = pari(a*d) sage: B(f) a*d sage: A.<a,b> = PolynomialRing(QQ) sage: B.<d,e> = PolynomialRing(A) sage: f = pari(a*d) sage: B(f) a*d It is possible to convert `f` into `B` by using ``f.sage()``, but this requires specifying a ``locals`` argument:: sage: f d*a sage: f.sage() Traceback (most recent call last): ... NameError: name 'd' is not defined sage: f.sage(locals={'a': a, 'd': d}) a*d """ from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict import sage.rings.polynomial.polynomial_element as polynomial_element # handle constants that coerce into self.base_ring() first, if possible if isinstance(x, Element) and x.parent() is self.base_ring(): # A Constant multi-polynomial return self({self._zero_tuple: x}) try: y = self.base_ring()._coerce_(x) return MPolynomial_polydict(self, {self._zero_tuple: y}) except TypeError: pass from multi_polynomial_libsingular import MPolynomial_libsingular if isinstance(x, MPolynomial_polydict): P = x.parent() if P is self: return x elif P == self: return MPolynomial_polydict(self, x.element().dict()) elif self.base_ring().has_coerce_map_from(P): # it might be in the base ring (i.e. a poly ring over a poly ring) c = self.base_ring()(x) return MPolynomial_polydict(self, {self._zero_tuple: c}) elif len(P.variable_names()) == len(self.variable_names()): # Map the variables in some crazy way (but in order, # of course). This is here since R(blah) is supposed # to be "make an element of R if at all possible with # no guarantees that this is mathematically solid." K = self.base_ring() D = x.element().dict() for i, a in D.iteritems(): D[i] = K(a) return MPolynomial_polydict(self, D) elif set(P.variable_names()).issubset(set(self.variable_names( ))) and self.base_ring().has_coerce_map_from(P.base_ring()): # If the named variables are a superset of the input, map the variables by name return MPolynomial_polydict(self, self._extract_polydict(x)) else: return MPolynomial_polydict( self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) elif isinstance(x, MPolynomial_libsingular): P = x.parent() if P == self: return MPolynomial_polydict(self, x.dict()) elif self.base_ring().has_coerce_map_from(P): # it might be in the base ring (i.e. a poly ring over a poly ring) c = self.base_ring()(x) return MPolynomial_polydict(self, {self._zero_tuple: c}) elif len(P.variable_names()) == len(self.variable_names()): # Map the variables in some crazy way (but in order, # of course). This is here since R(blah) is supposed # to be "make an element of R if at all possible with # no guarantees that this is mathematically solid." K = self.base_ring() D = x.dict() for i, a in D.iteritems(): D[i] = K(a) return MPolynomial_polydict(self, D) elif set(P.variable_names()).issubset(set(self.variable_names( ))) and self.base_ring().has_coerce_map_from(P.base_ring()): # If the named variables are a superset of the input, map the variables by name return MPolynomial_polydict(self, self._extract_polydict(x)) else: return MPolynomial_polydict( self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) elif isinstance(x, polynomial_element.Polynomial): return MPolynomial_polydict( self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) elif isinstance(x, PolyDict): return MPolynomial_polydict(self, x) elif isinstance(x, fraction_field_element.FractionFieldElement ) and x.parent().ring() == self: if x.denominator() == 1: return x.numerator() else: raise TypeError( "unable to coerce since the denominator is not 1") elif is_SingularElement(x) and self._has_singular: self._singular_().set_ring() try: return x.sage_poly(self) except TypeError: raise TypeError("unable to coerce singular object") elif hasattr(x, '_polynomial_'): return x._polynomial_(self) elif isinstance(x, str): from sage.misc.sage_eval import sage_eval try: x = sage_eval(x, self.gens_dict_recursive()) except NameError: raise TypeError("unable to evaluate {!r} in {}".format( x, self)) return self(x) elif is_Macaulay2Element(x): try: s = x.sage_polystring() if len(s) == 0: raise TypeError # NOTE: It's CRUCIAL to use the eval command as follows, # i.e., with the gen dict as the third arg and the second # empty. Otherwise pickling won't work after calls to this eval!!! # This took a while to figure out! return self(eval(s, {}, self.gens_dict())) except (AttributeError, TypeError, NameError, SyntaxError): raise TypeError("Unable to coerce macaulay2 object") return MPolynomial_polydict(self, x) elif isinstance(x, pari_gen) and x.type() == 't_POL': # This recursive approach is needed because PARI # represents multivariate polynomials as iterated # univariate polynomials. Below, v is the variable # with highest priority, and the x[i] are expressions # in the remaining variables. v = self.gens_dict_recursive()[str(x.variable())] return sum(self(x[i]) * v**i for i in xrange(x.poldegree() + 1)) if isinstance(x, dict): return MPolynomial_polydict(self, x) else: c = self.base_ring()(x) return MPolynomial_polydict(self, {self._zero_tuple: c})
class MPolynomialRing_polydict( MPolynomialRing_macaulay2_repr, PolynomialRing_singular_repr, MPolynomialRing_generic): """ Multivariable polynomial ring. EXAMPLES:: sage: R = PolynomialRing(Integers(12), 'x', 5); R Multivariate Polynomial Ring in x0, x1, x2, x3, x4 over Ring of integers modulo 12 sage: loads(R.dumps()) == R True """ def __init__(self, base_ring, n, names, order): from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular order = TermOrder(order,n) MPolynomialRing_generic.__init__(self, base_ring, n, names, order) # Construct the generators v = [0 for _ in xrange(n)] one = base_ring(1); self._gens = [] C = self._poly_class() for i in xrange(n): v[i] = 1 # int's! self._gens.append(C(self, {tuple(v):one})) v[i] = 0 self._gens = tuple(self._gens) self._zero_tuple = tuple(v) self._has_singular = can_convert_to_singular(self) # This polynomial ring should belong to Algebras(base_ring). # Algebras(...).parent_class, which was called from MPolynomialRing_generic.__init__, # tries to provide a conversion from the base ring, if it does not exist. # This is for algebras that only do the generic stuff in their initialisation. # But here, we want to use PolynomialBaseringInjection. Hence, we need to # wipe the memory and construct the conversion from scratch. if n: from sage.rings.polynomial.polynomial_element import PolynomialBaseringInjection base_inject = PolynomialBaseringInjection(base_ring, self) self.register_coercion(base_inject) def _monomial_order_function(self): return self.__monomial_order_function def _poly_class(self): from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict return MPolynomial_polydict def __cmp__(left, right): if not is_MPolynomialRing(right): return cmp(type(left),type(right)) else: return cmp((left.base_ring(), left.ngens(), left.variable_names(), left.term_order()), (right.base_ring(), right.ngens(), right.variable_names(), right.term_order())) def __call__(self, x, check=True): """ Convert ``x`` to an element of this multivariate polynomial ring, possibly non-canonically. EXAMPLES: We create a Macaulay2 multivariate polynomial via ideal arithmetic, then convert it into R. :: sage: R.<x,y> = PolynomialRing(QQ, 2) # optional sage: I = R.ideal([x^3 + y, y]) # optional sage: S = I._macaulay2_() # optional sage: T = S*S*S # optional sage: U = T.gens().entries().flatten() # optional sage: f = U[2]; f # optional x^6*y+2*x^3*y^2+y^3 sage: R(repr(f)) # optional x^6*y + 2*x^3*y^2 + y^3 Some other subtle conversions. We create polynomial rings in 2 variables over the rationals, integers, and a finite field. :: sage: R.<x,y> = QQ[] sage: S.<x,y> = ZZ[] sage: T.<x,y> = GF(7)[] We convert from integer polynomials to rational polynomials, and back:: sage: f = R(S.0^2 - 4*S.1^3); f -4*y^3 + x^2 sage: parent(f) Multivariate Polynomial Ring in x, y over Rational Field sage: parent(S(f)) Multivariate Polynomial Ring in x, y over Integer Ring We convert from polynomials over the finite field. :: sage: f = R(T.0^2 - 4*T.1^3); f 3*y^3 + x^2 sage: parent(f) Multivariate Polynomial Ring in x, y over Rational Field We dump and load the polynomial ring S:: sage: S2 = loads(dumps(S)) sage: S2 == S True Coerce works and gets the right parent. :: sage: parent(S2._coerce_(S.0)) is S2 True Conversion to reduce modulo a prime between rings with different variable names:: sage: R.<x,y> = PolynomialRing(QQ,2) sage: S.<a,b> = PolynomialRing(GF(7),2) sage: f = x^2 + 2/3*y^3 sage: S(f) 3*b^3 + a^2 Conversion from symbolic variables:: sage: x,y,z = var('x,y,z') sage: R = QQ[x,y,z] sage: type(x) <type 'sage.symbolic.expression.Expression'> sage: type(R(x)) <type 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'> sage: f = R(x^3 + y^3 - z^3); f x^3 + y^3 - z^3 sage: type(f) <type 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'> sage: parent(f) Multivariate Polynomial Ring in x, y, z over Rational Field A more complicated symbolic and computational mix. Behind the scenes Singular and Maxima are doing the real work. :: sage: R = QQ[x,y,z] sage: f = (x^3 + y^3 - z^3)^10; f (x^3 + y^3 - z^3)^10 sage: g = R(f); parent(g) Multivariate Polynomial Ring in x, y, z over Rational Field sage: (f - g).expand() 0 It intelligently handles conversions from polynomial rings in a subset of the variables too. :: sage: R = GF(5)['x,y,z'] sage: S = ZZ['y'] sage: R(7*S.0) 2*y sage: T = ZZ['x,z'] sage: R(2*T.0 + 6*T.1 + T.0*T.1^2) x*z^2 + 2*x + z :: sage: R = QQ['t,x,y,z'] sage: S.<x> = ZZ['x'] sage: T.<z> = S['z'] sage: T Univariate Polynomial Ring in z over Univariate Polynomial Ring in x over Integer Ring sage: f = (x+3*z+5)^2; f 9*z^2 + (6*x + 30)*z + x^2 + 10*x + 25 sage: R(f) x^2 + 6*x*z + 9*z^2 + 10*x + 30*z + 25 Arithmetic with a constant from a base ring:: sage: R.<u,v> = QQ[] sage: S.<x,y> = R[] sage: u^3*x^2 + v*y u^3*x^2 + v*y Stacked polynomial rings convert into constants if possible. First, the univariate case:: sage: R.<x> = QQ[] sage: S.<u,v> = R[] sage: S(u + 2) u + 2 sage: S(u + 2).degree() 1 sage: S(x + 3) x + 3 sage: S(x + 3).degree() 0 Second, the multivariate case:: sage: R.<x,y> = QQ[] sage: S.<u,v> = R[] sage: S(x + 2*y) x + 2*y sage: S(u + 2*v) u + 2*v Conversion from strings:: sage: R.<x,y> = QQ[] sage: R('x+(1/2)*y^2') 1/2*y^2 + x sage: S.<u,v> = ZZ[] sage: S('u^2 + u*v + v^2') u^2 + u*v + v^2 Foreign polynomial rings convert into the highest ring; the point here is that an element of T could convert to an element of R or an element of S; it is anticipated that an element of T is more likely to be "the right thing" and is historically consistent. :: sage: R.<x,y> = QQ[] sage: S.<u,v> = R[] sage: T.<a,b> = QQ[] sage: S(a + b) u + v TESTS: Check if we still allow nonsense :trac:`7951`:: sage: P = PolynomialRing(QQ, 0, '') sage: P('pi') Traceback (most recent call last): ... TypeError: Unable to coerce pi (<class 'sage.symbolic.constants.Pi'>) to Rational Check that it is possible to convert strings to iterated polynomial rings :trac:`13327`:: sage: Rm = QQ["a"]["b, c"] sage: Rm("a*b") a*b sage: parent(_) is Rm True """ from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict import sage.rings.polynomial.polynomial_element as polynomial_element # handle constants that coerce into self.base_ring() first, if possible if isinstance(x, Element) and x.parent() is self.base_ring(): # A Constant multi-polynomial return self({self._zero_tuple:x}) try: y = self.base_ring()._coerce_(x) return MPolynomial_polydict(self, {self._zero_tuple:y}) except TypeError: pass from multi_polynomial_libsingular import MPolynomial_libsingular if isinstance(x, MPolynomial_polydict): P = x.parent() if P is self: return x elif P == self: return MPolynomial_polydict(self, x.element().dict()) elif self.base_ring().has_coerce_map_from(P): # it might be in the base ring (i.e. a poly ring over a poly ring) c = self.base_ring()(x) return MPolynomial_polydict(self, {self._zero_tuple:c}) elif len(P.variable_names()) == len(self.variable_names()): # Map the variables in some crazy way (but in order, # of course). This is here since R(blah) is supposed # to be "make an element of R if at all possible with # no guarantees that this is mathematically solid." K = self.base_ring() D = x.element().dict() for i, a in D.iteritems(): D[i] = K(a) return MPolynomial_polydict(self, D) elif set(P.variable_names()).issubset(set(self.variable_names())) and self.base_ring().has_coerce_map_from(P.base_ring()): # If the named variables are a superset of the input, map the variables by name return MPolynomial_polydict(self, self._extract_polydict(x)) else: return MPolynomial_polydict(self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) elif isinstance(x, MPolynomial_libsingular): P = x.parent() if P == self: return MPolynomial_polydict(self, x.dict()) elif self.base_ring().has_coerce_map_from(P): # it might be in the base ring (i.e. a poly ring over a poly ring) c = self.base_ring()(x) return MPolynomial_polydict(self, {self._zero_tuple:c}) elif len(P.variable_names()) == len(self.variable_names()): # Map the variables in some crazy way (but in order, # of course). This is here since R(blah) is supposed # to be "make an element of R if at all possible with # no guarantees that this is mathematically solid." K = self.base_ring() D = x.dict() for i, a in D.iteritems(): D[i] = K(a) return MPolynomial_polydict(self, D) elif set(P.variable_names()).issubset(set(self.variable_names())) and self.base_ring().has_coerce_map_from(P.base_ring()): # If the named variables are a superset of the input, map the variables by name return MPolynomial_polydict(self, self._extract_polydict(x)) else: return MPolynomial_polydict(self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) elif isinstance(x, polynomial_element.Polynomial): return MPolynomial_polydict(self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) elif isinstance(x, PolyDict): return MPolynomial_polydict(self, x) elif isinstance(x, fraction_field_element.FractionFieldElement) and x.parent().ring() == self: if x.denominator() == 1: return x.numerator() else: raise TypeError, "unable to coerce since the denominator is not 1" elif is_SingularElement(x) and self._has_singular: self._singular_().set_ring() try: return x.sage_poly(self) except TypeError: raise TypeError, "unable to coerce singular object" elif hasattr(x, '_polynomial_'): return x._polynomial_(self) elif isinstance(x, str): try: from sage.misc.sage_eval import sage_eval return self(sage_eval(x, self.gens_dict_recursive())) except NameError, e: raise TypeError, "unable to convert string" elif is_Macaulay2Element(x): try: s = x.sage_polystring() if len(s) == 0: raise TypeError # NOTE: It's CRUCIAL to use the eval command as follows, # i.e., with the gen dict as the third arg and the second # empty. Otherwise pickling won't work after calls to this eval!!! # This took a while to figure out! return self(eval(s, {}, self.gens_dict())) except (AttributeError, TypeError, NameError, SyntaxError): raise TypeError, "Unable to coerce macaulay2 object" return MPolynomial_polydict(self, x)