source: sage/rings/polynomial/multi_polynomial_ring_generic.pyx @ 5646:c62e71753f48

Revision 5646:c62e71753f48, 11.5 KB checked in by 'Martin Albrecht <malb@…, 6 years ago (diff)

bugfixes for MPolynomials

Line 
1include '../../ext/stdsage.pxi'
2
3from sage.structure.parent_gens cimport ParentWithGens
4import sage.misc.latex
5import multi_polynomial_ideal
6from term_order import TermOrder
7from sage.rings.integer_ring import ZZ
8from sage.rings.polynomial.polydict import PolyDict
9import multi_polynomial_element
10
11def is_MPolynomialRing(x):
12    return bool(PY_TYPE_CHECK(x, MPolynomialRing_generic))
13
14cdef class MPolynomialRing_generic(sage.rings.ring.CommutativeRing):
15    def __init__(self, base_ring, n, names, order):
16        order = TermOrder(order,n)
17        if not isinstance(base_ring, sage.rings.ring.CommutativeRing):
18            raise TypeError, "Base ring must be a commutative ring."
19        n = int(n)
20        if n < 0:
21            raise ValueError, "Multivariate Polynomial Rings must " + \
22                  "have more than 0 variables."
23        self.__ngens = n
24        self.__term_order = order
25        self._has_singular = False #cannot convert to Singular by default
26        ParentWithGens.__init__(self, base_ring, names)
27
28    def is_integral_domain(self):
29        return self.base_ring().is_integral_domain()
30           
31    cdef _coerce_c_impl(self, x):
32        """
33        Return the canonical coercion of x to this multivariate
34        polynomial ring, if one is defined, or raise a TypeError.
35
36        The rings that canonically coerce to this polynomial ring are:
37            * this ring itself
38            * polynomial rings in the same variables over any base ring that
39              canonically coerces to the base ring of this ring
40            * any ring that canonically coerces to the base ring of this
41              polynomial ring.
42
43        TESTS:
44        This fairly complicated code (from Michel Vandenbergh) ends up
45        imlicitly calling _coerce_c_impl:
46            sage: z = polygen(QQ, 'z')
47            sage: W.<s>=NumberField(z^2+1)
48            sage: Q.<u,v,w> = W[]
49            sage: W1 = FractionField (Q)
50            sage: S.<x,y,z> = W1[]
51            sage: u + x
52            x + u
53            sage: x + 1/u
54            x + 1/u
55        """
56        try:
57            P = x.parent()
58            # polynomial rings in the same variable over the any base that coerces in:
59            if is_MPolynomialRing(P):
60                if P.variable_names() == self.variable_names():
61                    if self.has_coerce_map_from(P.base_ring()):
62                        return self(x)
63
64        except AttributeError:
65            pass
66
67        # any ring that coerces to the base ring of this polynomial ring.
68        return self._coerce_try(x, [self.base_ring()])
69
70    def __richcmp__(left, right, int op):
71        return (<ParentWithGens>left)._richcmp(right, op)
72   
73    cdef int _cmp_c_impl(left, Parent right) except -2:
74        if not is_MPolynomialRing(right):
75            return cmp(type(left),type(right))
76        else:
77            return cmp((left.base_ring(), left.__ngens, left.variable_names(), left.__term_order),
78                       (right.base_ring(), (<MPolynomialRing_generic>right).__ngens, right.variable_names(), (<MPolynomialRing_generic>right).__term_order))
79
80    def __contains__(self, x):
81        """
82        This definition of containment does not involve a natural
83        inclusion from rings with less variables into rings with more.
84        """
85        try:
86            return x.parent() == self
87        except AttributeError:
88            return False
89
90    def _repr_(self):
91        return "Polynomial Ring in %s over %s"%(", ".join(self.variable_names()), self.base_ring())
92
93    def _latex_(self):
94        vars = str(self.latex_variable_names()).replace('\n','').replace("'",'')
95        return "%s[%s]"%(sage.misc.latex.latex(self.base_ring()), vars[1:-1])
96
97
98    def _ideal_class_(self):
99        return multi_polynomial_ideal.MPolynomialIdeal
100   
101    def _is_valid_homomorphism_(self, codomain, im_gens):
102        try:
103            # all that is needed is that elements of the base ring
104            # of the polynomial ring canonically coerce into codomain.
105            # Since poly rings are free, any image of the gen
106            # determines a homomorphism
107            codomain._coerce_(self.base_ring()(1))
108        except TypeError:
109            return False
110        return True
111
112    def _magma_(self, magma=None):
113        """
114        Used in converting this ring to the corresponding ring in MAGMA.
115
116        EXAMPLES:
117            sage: R.<y,z,w> = PolynomialRing(QQ,3)
118            sage: magma(R) # optional
119            Polynomial ring of rank 3 over Rational Field
120            Graded Reverse Lexicographical Order
121            Variables: y, z, w
122
123            sage: magma(PolynomialRing(GF(7),4, 'x')) #optional
124            Polynomial ring of rank 4 over GF(7)
125            Graded Reverse Lexicographical Order
126            Variables: x0, x1, x2, x3
127
128            sage: magma(PolynomialRing(GF(49,'a'),10, 'x')) #optional
129            Polynomial ring of rank 10 over GF(7^2)
130            Graded Reverse Lexicographical Order
131            Variables: x0, x1, x2, x3, x4, x5, x6, x7, x8, x9
132
133            sage: magma(PolynomialRing(ZZ['a,b,c'],3, 'x')) #optional
134            Polynomial ring of rank 3 over Polynomial ring of rank 3 over Integer Ring
135            Graded Reverse Lexicographical Order
136            Variables: x0, x1, x2
137        """
138        if magma == None:
139            import sage.interfaces.magma
140            magma = sage.interfaces.magma.magma
141       
142        try:
143            if self.__magma is None:
144                raise AttributeError
145            m = self.__magma
146            m._check_valid()
147            if not m.parent() is magma:
148                raise ValueError
149            return m
150        except (AttributeError,ValueError):
151            B = magma(self.base_ring())
152            R = magma('PolynomialRing(%s, %s, %s)'%(B.name(), self.ngens(),self.term_order().magma_str()))
153            R.assign_names(self.variable_names())
154            self.__magma = R
155            return R
156
157    def _magma_init_(self):
158        B = self.base_ring()._magma_init_()
159        R = 'PolynomialRing(%s, %s, %s)'%(B, self.ngens(),self.term_order().magma_str())
160        return R
161   
162    def is_finite(self):
163        if self.ngens() == 0:
164            return self.base_ring().is_finite()
165        return False
166   
167    def is_field(self):
168        """
169        Return True if this multivariate polynomial ring is a field, i.e.,
170        it is a ring in 0 generators over a field.
171        """
172        if self.ngens() == 0:
173            return self.base_ring().is_field()
174        return False
175
176    def term_order(self):
177        return self.__term_order
178
179    def characteristic(self):
180        """
181        Return the characteristic of this polynomial ring.
182
183        EXAMPLES:
184            sage: R = MPolynomialRing(QQ, 'x', 3)
185            sage: R.characteristic()
186            0
187            sage: R = MPolynomialRing(GF(7),'x', 20)
188            sage: R.characteristic()
189            7
190        """
191        return self.base_ring().characteristic()
192
193    def gen(self, n=0):
194        if n < 0 or n >= self.__ngens:
195            raise ValueError, "Generator not defined."
196        return self._gens[int(n)]
197
198    def gens(self):
199        return self._gens
200
201    def krull_dimension(self):
202        return self.base_ring().krull_dimension() + self.ngens()
203
204    def ngens(self):
205        return self.__ngens
206
207    def _monomial_order_function(self):
208        raise NotImplementedError
209
210    def latex_variable_names(self):
211        """
212        Returns the list of variable names suitable for latex output.
213
214        All '_SOMETHING' substrings are replaced by '_{SOMETHING}' recursively
215        so that subscripts of subscripts work.
216
217        EXAMPLES:
218            sage: R, x = PolynomialRing(QQ,'x',12).objgens()
219            sage: x
220            (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11)
221            sage: print R.latex_variable_names ()
222            ['x_{0}', 'x_{1}', 'x_{2}', 'x_{3}', 'x_{4}', 'x_{5}', 'x_{6}', 'x_{7}', 'x_{8}', 'x_{9}', 'x_{10}', 'x_{11}']
223            sage: f = x[0]^3 + 15/3 * x[1]^10
224            sage: print latex(f)
225            5 x_{1}^{10} + x_{0}^{3}
226        """
227        if self._latex_names is not None:
228            return self._latex_names
229        names = []
230        for g in self.variable_names():
231            i = len(g)-1
232            while i >= 0 and g[i].isdigit():
233                i -= 1
234            if i < len(g)-1:
235                g = '%s_{%s}'%(g[:i+1], g[i+1:])
236            names.append(g)
237        self._latex_names = names
238        return names
239
240    def __reduce__(self):
241        """
242        """
243
244        base_ring = self.base_ring()
245        n = self.ngens()
246        names = self.variable_names()
247        order = self.term_order()
248       
249        return unpickle_MPolynomialRing_generic_v1,(base_ring, n, names, order)
250
251
252    def random_element(self, degree=2, terms=5, *args, **kwds):
253        r"""
254        Return a random polynomial in this polynomial ring.
255       
256        INPUT:
257            degree -- maximum total degree of resulting polynomial
258            terms  -- maximum number of terms to generate
259
260        OUTPUT: a random polynomial of total degree \code{degree}
261                and with \code{term} terms in it.
262
263        EXAMPLES:
264            sage: [QQ['x,y'].random_element() for _ in range(5)]
265            [-1/14*x*y + 1/2*x, x*y + x - y + 1, 3*x*y + x - 1/2, 1/3*x*y - 5*x + 1/2*y + 7/6, 2*x*y + 1/2*x + 1]
266            sage: R = MPolynomialRing(ZZ, 'x,y',2 );
267            sage: R.random_element(2)          # random
268            -1*x*y + x + 15*y - 2
269            sage: R.random_element(12)         # random
270            x^4*y^5 + x^3*y^5 + 6*x^2*y^2 - x^2
271            sage: R.random_element(12,3)       # random
272            -3*x^4*y^2 - x^5 - x^4*y
273            sage: R.random_element(3)          # random
274            2*y*z + 2*x + 2*y
275
276            sage: R.<x,y> = MPolynomialRing(RR)
277            sage: R.random_element(2)          # random
278            -0.645358174399450*x*y + 0.572655401740132*x + 0.197478565033010
279
280            sage: R.random_element(41)         # random
281            -4*x^6*y^4*z^4*a^6*b^3*c^6*d^5 + 1/2*x^4*y^3*z^5*a^4*c^5*d^6 - 5*x^3*z^3*a^6*b^4*c*d^5 + 10*x^2*y*z^5*a^4*b^2*c^3*d^4 - 5*x^3*y^5*z*b^2*c^5*d
282
283        AUTHOR:
284            -- didier deshommes
285        """
286        # General strategy:
287        # generate n-tuples of numbers with each element in the tuple
288        # not greater than  (degree/n) so that the degree
289        # (ie, the sum of the elements in the tuple) does not exceed
290        # their total degree
291       
292        n = self.__ngens         # length of the n-tuple
293        max_deg = int(degree/n)  # max degree for each term
294        R = self.base_ring()
295       
296        # restrict exponents to positive integers only
297        exponents = [ tuple([ZZ.random_element(0,max_deg+1) for _ in range(n)])
298                       for _ in range(terms) ]
299        coeffs = []
300        for _ in range(terms):
301            c = R.random_element(*args,**kwds)
302            while not c:
303                c = R.random_element(*args,**kwds)
304            coeffs.append(c) # allow only nonzero coefficients
305
306        d = dict( zip(tuple(exponents), coeffs) )
307        return self(multi_polynomial_element.MPolynomial_polydict(self, PolyDict(d)))
308       
309       
310####################
311# Leave *all* old versions!
312
313def unpickle_MPolynomialRing_generic_v1(base_ring, n, names, order):
314    from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing
315    return MPolynomialRing(base_ring, n, names=names, order=order)
316
317
318def unpickle_MPolynomialRing_generic(base_ring, n, names, order):
319    from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing
320   
321    return MPolynomialRing(base_ring, n, names=names, order=order)
Note: See TracBrowser for help on using the repository browser.