| 1 | include '../../ext/stdsage.pxi' |
|---|
| 2 | |
|---|
| 3 | from sage.structure.parent_gens cimport ParentWithGens |
|---|
| 4 | import sage.misc.latex |
|---|
| 5 | import multi_polynomial_ideal |
|---|
| 6 | from term_order import TermOrder |
|---|
| 7 | from sage.rings.integer_ring import ZZ |
|---|
| 8 | from sage.rings.polynomial.polydict import PolyDict |
|---|
| 9 | import multi_polynomial_element |
|---|
| 10 | import polynomial_ring |
|---|
| 11 | |
|---|
| 12 | def is_MPolynomialRing(x): |
|---|
| 13 | return bool(PY_TYPE_CHECK(x, MPolynomialRing_generic)) |
|---|
| 14 | |
|---|
| 15 | cdef class MPolynomialRing_generic(sage.rings.ring.CommutativeRing): |
|---|
| 16 | def __init__(self, base_ring, n, names, order): |
|---|
| 17 | order = TermOrder(order,n) |
|---|
| 18 | if not isinstance(base_ring, sage.rings.ring.CommutativeRing): |
|---|
| 19 | raise TypeError, "Base ring must be a commutative ring." |
|---|
| 20 | n = int(n) |
|---|
| 21 | if n < 0: |
|---|
| 22 | raise ValueError, "Multivariate Polynomial Rings must " + \ |
|---|
| 23 | "have more than 0 variables." |
|---|
| 24 | self.__ngens = n |
|---|
| 25 | self.__term_order = order |
|---|
| 26 | self._has_singular = False #cannot convert to Singular by default |
|---|
| 27 | ParentWithGens.__init__(self, base_ring, names) |
|---|
| 28 | |
|---|
| 29 | def is_integral_domain(self): |
|---|
| 30 | """ |
|---|
| 31 | EXAMPLES: |
|---|
| 32 | sage: ZZ['x,y'].is_integral_domain() |
|---|
| 33 | True |
|---|
| 34 | sage: Integers(8)['x,y'].is_integral_domain() |
|---|
| 35 | False |
|---|
| 36 | """ |
|---|
| 37 | return self.base_ring().is_integral_domain() |
|---|
| 38 | |
|---|
| 39 | def is_noetherian(self): |
|---|
| 40 | """ |
|---|
| 41 | EXAMPLES: |
|---|
| 42 | sage: ZZ['x,y'].is_noetherian() |
|---|
| 43 | True |
|---|
| 44 | sage: Integers(8)['x,y'].is_noetherian() |
|---|
| 45 | True |
|---|
| 46 | """ |
|---|
| 47 | return self.base_ring().is_noetherian() |
|---|
| 48 | |
|---|
| 49 | def construction(self): |
|---|
| 50 | """ |
|---|
| 51 | Returns a functor F and basering R such that F(R) == self. |
|---|
| 52 | |
|---|
| 53 | In the multi-variate case, R is a polynomial ring with one |
|---|
| 54 | less variable, and F knows to adjoin the variable in the |
|---|
| 55 | correct way. |
|---|
| 56 | |
|---|
| 57 | EXAMPLES: |
|---|
| 58 | sage: S = ZZ['x,y'] |
|---|
| 59 | sage: F, R = S.construction(); R |
|---|
| 60 | Univariate Polynomial Ring in x over Integer Ring |
|---|
| 61 | sage: F(R) == S |
|---|
| 62 | True |
|---|
| 63 | sage: F(R) == ZZ['x']['y'] |
|---|
| 64 | False |
|---|
| 65 | |
|---|
| 66 | """ |
|---|
| 67 | from sage.rings.polynomial.polynomial_ring import PolynomialRing |
|---|
| 68 | from sage.categories.pushout import PolynomialFunctor |
|---|
| 69 | vars = self.variable_names() |
|---|
| 70 | if len(vars) == 1: |
|---|
| 71 | return PolynomialFunctor(vars[0], False), self.base_ring() |
|---|
| 72 | else: |
|---|
| 73 | return PolynomialFunctor(vars[-1], True), PolynomialRing(self.base_ring(), vars[:-1]) |
|---|
| 74 | |
|---|
| 75 | def completion(self, p, prec=20, extras=None): |
|---|
| 76 | try: |
|---|
| 77 | from sage.rings.power_series_ring import PowerSeriesRing |
|---|
| 78 | return PowerSeriesRing(self.remove_var(p), p, prec) |
|---|
| 79 | except ValueError: |
|---|
| 80 | raise TypeError, "Cannot complete %s with respect to %s" % (self, p) |
|---|
| 81 | |
|---|
| 82 | def remove_var(self, var): |
|---|
| 83 | vars = list(self.variable_names()) |
|---|
| 84 | vars.remove(str(var)) |
|---|
| 85 | from sage.rings.polynomial.polynomial_ring import PolynomialRing |
|---|
| 86 | return PolynomialRing(self.base_ring(), vars) |
|---|
| 87 | |
|---|
| 88 | cdef _coerce_c_impl(self, x): |
|---|
| 89 | """ |
|---|
| 90 | Return the canonical coercion of x to this multivariate |
|---|
| 91 | polynomial ring, if one is defined, or raise a TypeError. |
|---|
| 92 | |
|---|
| 93 | The rings that canonically coerce to this polynomial ring are: |
|---|
| 94 | * this ring itself |
|---|
| 95 | * polynomial rings in the same variables over any base ring that |
|---|
| 96 | canonically coerces to the base ring of this ring |
|---|
| 97 | * polynomial rings in a subset of the variables over any base ring that |
|---|
| 98 | canonically coerces to the base ring of this ring |
|---|
| 99 | * any ring that canonically coerces to the base ring of this |
|---|
| 100 | polynomial ring. |
|---|
| 101 | |
|---|
| 102 | TESTS: |
|---|
| 103 | This fairly complicated code (from Michel Vandenbergh) ends up |
|---|
| 104 | imlicitly calling _coerce_c_impl: |
|---|
| 105 | sage: z = polygen(QQ, 'z') |
|---|
| 106 | sage: W.<s>=NumberField(z^2+1) |
|---|
| 107 | sage: Q.<u,v,w> = W[] |
|---|
| 108 | sage: W1 = FractionField (Q) |
|---|
| 109 | sage: S.<x,y,z> = W1[] |
|---|
| 110 | sage: u + x |
|---|
| 111 | x + u |
|---|
| 112 | sage: x + 1/u |
|---|
| 113 | x + 1/u |
|---|
| 114 | """ |
|---|
| 115 | try: |
|---|
| 116 | P = x.parent() |
|---|
| 117 | # polynomial rings in the same variable over the any base that coerces in: |
|---|
| 118 | if is_MPolynomialRing(P): |
|---|
| 119 | if P.variable_names() == self.variable_names(): |
|---|
| 120 | if self.has_coerce_map_from(P.base_ring()): |
|---|
| 121 | return self(x) |
|---|
| 122 | elif self.base_ring().has_coerce_map_from(P._mpoly_base_ring(self.variable_names())): |
|---|
| 123 | return self(x) |
|---|
| 124 | |
|---|
| 125 | elif polynomial_ring.is_PolynomialRing(P): |
|---|
| 126 | if P.variable_name() in self.variable_names(): |
|---|
| 127 | if self.has_coerce_map_from(P.base_ring()): |
|---|
| 128 | return self(x) |
|---|
| 129 | |
|---|
| 130 | except AttributeError: |
|---|
| 131 | pass |
|---|
| 132 | |
|---|
| 133 | # any ring that coerces to the base ring of this polynomial ring. |
|---|
| 134 | return self._coerce_try(x, [self.base_ring()]) |
|---|
| 135 | |
|---|
| 136 | def _extract_polydict(self, x): |
|---|
| 137 | """ |
|---|
| 138 | Assuming other_vars is a subset of self.variable_names(), |
|---|
| 139 | convert the dict of ETuples with respect to other_vars to |
|---|
| 140 | a dict with respect to self.variable_names() |
|---|
| 141 | """ |
|---|
| 142 | # This is probably horribly innefficient |
|---|
| 143 | from polydict import ETuple |
|---|
| 144 | other_vars = list(x.parent().variable_names()) |
|---|
| 145 | name_mapping = [(other_vars.index(var) if var in other_vars else -1) for var in self.variable_names()] |
|---|
| 146 | K = self.base_ring() |
|---|
| 147 | D = {} |
|---|
| 148 | var_range = range(len(self.variable_names())) |
|---|
| 149 | for ix, a in x.dict().iteritems(): |
|---|
| 150 | ix = ETuple([0 if name_mapping[t] == -1 else ix[name_mapping[t]] for t in var_range]) |
|---|
| 151 | D[ix] = K(a) |
|---|
| 152 | return D |
|---|
| 153 | |
|---|
| 154 | def __richcmp__(left, right, int op): |
|---|
| 155 | return (<ParentWithGens>left)._richcmp(right, op) |
|---|
| 156 | |
|---|
| 157 | cdef int _cmp_c_impl(left, Parent right) except -2: |
|---|
| 158 | if not is_MPolynomialRing(right): |
|---|
| 159 | return cmp(type(left),type(right)) |
|---|
| 160 | else: |
|---|
| 161 | return cmp((left.base_ring(), left.__ngens, left.variable_names(), left.__term_order), |
|---|
| 162 | (right.base_ring(), (<MPolynomialRing_generic>right).__ngens, right.variable_names(), (<MPolynomialRing_generic>right).__term_order)) |
|---|
| 163 | |
|---|
| 164 | def __contains__(self, x): |
|---|
| 165 | """ |
|---|
| 166 | This definition of containment does not involve a natural |
|---|
| 167 | inclusion from rings with less variables into rings with more. |
|---|
| 168 | """ |
|---|
| 169 | try: |
|---|
| 170 | return x.parent() == self |
|---|
| 171 | except AttributeError: |
|---|
| 172 | return False |
|---|
| 173 | |
|---|
| 174 | def _repr_(self): |
|---|
| 175 | return "Polynomial Ring in %s over %s"%(", ".join(self.variable_names()), self.base_ring()) |
|---|
| 176 | |
|---|
| 177 | def _latex_(self): |
|---|
| 178 | vars = str(self.latex_variable_names()).replace('\n','').replace("'",'') |
|---|
| 179 | return "%s[%s]"%(sage.misc.latex.latex(self.base_ring()), vars[1:-1]) |
|---|
| 180 | |
|---|
| 181 | |
|---|
| 182 | def _ideal_class_(self): |
|---|
| 183 | return multi_polynomial_ideal.MPolynomialIdeal |
|---|
| 184 | |
|---|
| 185 | def _is_valid_homomorphism_(self, codomain, im_gens): |
|---|
| 186 | try: |
|---|
| 187 | # all that is needed is that elements of the base ring |
|---|
| 188 | # of the polynomial ring canonically coerce into codomain. |
|---|
| 189 | # Since poly rings are free, any image of the gen |
|---|
| 190 | # determines a homomorphism |
|---|
| 191 | codomain._coerce_(self.base_ring()(1)) |
|---|
| 192 | except TypeError: |
|---|
| 193 | return False |
|---|
| 194 | return True |
|---|
| 195 | |
|---|
| 196 | def _magma_(self, magma=None): |
|---|
| 197 | """ |
|---|
| 198 | Used in converting this ring to the corresponding ring in MAGMA. |
|---|
| 199 | |
|---|
| 200 | EXAMPLES: |
|---|
| 201 | sage: R.<y,z,w> = PolynomialRing(QQ,3) |
|---|
| 202 | sage: magma(R) # optional |
|---|
| 203 | Polynomial ring of rank 3 over Rational Field |
|---|
| 204 | Graded Reverse Lexicographical Order |
|---|
| 205 | Variables: y, z, w |
|---|
| 206 | |
|---|
| 207 | sage: magma(PolynomialRing(GF(7),4, 'x')) #optional |
|---|
| 208 | Polynomial ring of rank 4 over GF(7) |
|---|
| 209 | Graded Reverse Lexicographical Order |
|---|
| 210 | Variables: x0, x1, x2, x3 |
|---|
| 211 | |
|---|
| 212 | sage: magma(PolynomialRing(GF(49,'a'),10, 'x')) #optional |
|---|
| 213 | Polynomial ring of rank 10 over GF(7^2) |
|---|
| 214 | Graded Reverse Lexicographical Order |
|---|
| 215 | Variables: x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 |
|---|
| 216 | |
|---|
| 217 | sage: magma(PolynomialRing(ZZ['a,b,c'],3, 'x')) #optional |
|---|
| 218 | Polynomial ring of rank 3 over Polynomial ring of rank 3 over Integer Ring |
|---|
| 219 | Graded Reverse Lexicographical Order |
|---|
| 220 | Variables: x0, x1, x2 |
|---|
| 221 | """ |
|---|
| 222 | if magma == None: |
|---|
| 223 | import sage.interfaces.magma |
|---|
| 224 | magma = sage.interfaces.magma.magma |
|---|
| 225 | |
|---|
| 226 | try: |
|---|
| 227 | if self.__magma is None: |
|---|
| 228 | raise AttributeError |
|---|
| 229 | m = self.__magma |
|---|
| 230 | m._check_valid() |
|---|
| 231 | if not m.parent() is magma: |
|---|
| 232 | raise ValueError |
|---|
| 233 | return m |
|---|
| 234 | except (AttributeError,ValueError): |
|---|
| 235 | B = magma(self.base_ring()) |
|---|
| 236 | R = magma('PolynomialRing(%s, %s, %s)'%(B.name(), self.ngens(),self.term_order().magma_str())) |
|---|
| 237 | R.assign_names(self.variable_names()) |
|---|
| 238 | self.__magma = R |
|---|
| 239 | return R |
|---|
| 240 | |
|---|
| 241 | def _magma_init_(self): |
|---|
| 242 | """ |
|---|
| 243 | Return a string representation of self MAGMA can understand. |
|---|
| 244 | """ |
|---|
| 245 | try: # we need that for GF(q) arithmetic |
|---|
| 246 | B = self.base_ring()._magma_().name() |
|---|
| 247 | except (RuntimeError,TypeError): |
|---|
| 248 | B = self.base_ring()._magma_init_() |
|---|
| 249 | R = 'PolynomialRing(%s, %s, %s)'%(B, self.ngens(),self.term_order().magma_str()) |
|---|
| 250 | return R |
|---|
| 251 | |
|---|
| 252 | def is_finite(self): |
|---|
| 253 | if self.ngens() == 0: |
|---|
| 254 | return self.base_ring().is_finite() |
|---|
| 255 | return False |
|---|
| 256 | |
|---|
| 257 | def is_field(self): |
|---|
| 258 | """ |
|---|
| 259 | Return True if this multivariate polynomial ring is a field, i.e., |
|---|
| 260 | it is a ring in 0 generators over a field. |
|---|
| 261 | """ |
|---|
| 262 | if self.ngens() == 0: |
|---|
| 263 | return self.base_ring().is_field() |
|---|
| 264 | return False |
|---|
| 265 | |
|---|
| 266 | def term_order(self): |
|---|
| 267 | return self.__term_order |
|---|
| 268 | |
|---|
| 269 | def characteristic(self): |
|---|
| 270 | """ |
|---|
| 271 | Return the characteristic of this polynomial ring. |
|---|
| 272 | |
|---|
| 273 | EXAMPLES: |
|---|
| 274 | sage: R = MPolynomialRing(QQ, 'x', 3) |
|---|
| 275 | sage: R.characteristic() |
|---|
| 276 | 0 |
|---|
| 277 | sage: R = MPolynomialRing(GF(7),'x', 20) |
|---|
| 278 | sage: R.characteristic() |
|---|
| 279 | 7 |
|---|
| 280 | """ |
|---|
| 281 | return self.base_ring().characteristic() |
|---|
| 282 | |
|---|
| 283 | def gen(self, n=0): |
|---|
| 284 | if n < 0 or n >= self.__ngens: |
|---|
| 285 | raise ValueError, "Generator not defined." |
|---|
| 286 | return self._gens[int(n)] |
|---|
| 287 | |
|---|
| 288 | def gens(self): |
|---|
| 289 | return self._gens |
|---|
| 290 | |
|---|
| 291 | def variable_names_recursive(self, depth=sage.rings.infinity.infinity): |
|---|
| 292 | r""" |
|---|
| 293 | Returns the list of variable names of this and its baserings, as if |
|---|
| 294 | it were a single multi-variate polynomial. |
|---|
| 295 | |
|---|
| 296 | EXAMPLES: |
|---|
| 297 | sage: R = QQ['x,y']['z,w'] |
|---|
| 298 | sage: R.variable_names_recursive() |
|---|
| 299 | ('x', 'y', 'z', 'w') |
|---|
| 300 | sage: R.variable_names_recursive(3) |
|---|
| 301 | ('y', 'z', 'w') |
|---|
| 302 | |
|---|
| 303 | """ |
|---|
| 304 | if depth <= 0: |
|---|
| 305 | all = () |
|---|
| 306 | elif depth == 1: |
|---|
| 307 | all = self.variable_names() |
|---|
| 308 | else: |
|---|
| 309 | my_vars = self.variable_names() |
|---|
| 310 | try: |
|---|
| 311 | all = self.base_ring().variable_names_recursive(depth - len(my_vars)) + my_vars |
|---|
| 312 | except AttributeError: |
|---|
| 313 | all = my_vars |
|---|
| 314 | if len(all) > depth: |
|---|
| 315 | all = all[-depth:] |
|---|
| 316 | return all |
|---|
| 317 | |
|---|
| 318 | def _mpoly_base_ring(self, vars=None): |
|---|
| 319 | """ |
|---|
| 320 | Returns the basering if this is viewed as a polynomial ring over vars. |
|---|
| 321 | See also MPolynomial._mpoly_dict_recursive |
|---|
| 322 | """ |
|---|
| 323 | if vars is None: |
|---|
| 324 | vars = self.variable_names_recursive() |
|---|
| 325 | vars = list(vars) |
|---|
| 326 | my_vars = list(self.variable_names()) |
|---|
| 327 | if vars == list(my_vars): |
|---|
| 328 | return self.base_ring() |
|---|
| 329 | elif not my_vars[-1] in vars: |
|---|
| 330 | return self |
|---|
| 331 | elif not set(my_vars).issubset(set(vars)): |
|---|
| 332 | while my_vars[-1] in vars: |
|---|
| 333 | my_vars.pop() |
|---|
| 334 | from polynomial_ring_constructor import PolynomialRing |
|---|
| 335 | return PolynomialRing(self.base_ring(), my_vars) |
|---|
| 336 | else: |
|---|
| 337 | try: |
|---|
| 338 | return self.base_ring()._mpoly_base_ring(vars[:vars.index(my_vars[0])]) |
|---|
| 339 | except AttributeError: |
|---|
| 340 | return self.base_ring() |
|---|
| 341 | |
|---|
| 342 | |
|---|
| 343 | def krull_dimension(self): |
|---|
| 344 | return self.base_ring().krull_dimension() + self.ngens() |
|---|
| 345 | |
|---|
| 346 | def ngens(self): |
|---|
| 347 | return self.__ngens |
|---|
| 348 | |
|---|
| 349 | def _monomial_order_function(self): |
|---|
| 350 | raise NotImplementedError |
|---|
| 351 | |
|---|
| 352 | def latex_variable_names(self): |
|---|
| 353 | """ |
|---|
| 354 | Returns the list of variable names suitable for latex output. |
|---|
| 355 | |
|---|
| 356 | All '_SOMETHING' substrings are replaced by '_{SOMETHING}' recursively |
|---|
| 357 | so that subscripts of subscripts work. |
|---|
| 358 | |
|---|
| 359 | EXAMPLES: |
|---|
| 360 | sage: R, x = PolynomialRing(QQ,'x',12).objgens() |
|---|
| 361 | sage: x |
|---|
| 362 | (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) |
|---|
| 363 | sage: print R.latex_variable_names () |
|---|
| 364 | ['x_{0}', 'x_{1}', 'x_{2}', 'x_{3}', 'x_{4}', 'x_{5}', 'x_{6}', 'x_{7}', 'x_{8}', 'x_{9}', 'x_{10}', 'x_{11}'] |
|---|
| 365 | sage: f = x[0]^3 + 15/3 * x[1]^10 |
|---|
| 366 | sage: print latex(f) |
|---|
| 367 | 5 x_{1}^{10} + x_{0}^{3} |
|---|
| 368 | """ |
|---|
| 369 | if self._latex_names is not None: |
|---|
| 370 | return self._latex_names |
|---|
| 371 | names = [] |
|---|
| 372 | for g in self.variable_names(): |
|---|
| 373 | i = len(g)-1 |
|---|
| 374 | while i >= 0 and g[i].isdigit(): |
|---|
| 375 | i -= 1 |
|---|
| 376 | if i < len(g)-1: |
|---|
| 377 | g = '%s_{%s}'%(g[:i+1], g[i+1:]) |
|---|
| 378 | names.append(g) |
|---|
| 379 | self._latex_names = names |
|---|
| 380 | return names |
|---|
| 381 | |
|---|
| 382 | def __reduce__(self): |
|---|
| 383 | """ |
|---|
| 384 | """ |
|---|
| 385 | |
|---|
| 386 | base_ring = self.base_ring() |
|---|
| 387 | n = self.ngens() |
|---|
| 388 | names = self.variable_names() |
|---|
| 389 | order = self.term_order() |
|---|
| 390 | |
|---|
| 391 | return unpickle_MPolynomialRing_generic_v1,(base_ring, n, names, order) |
|---|
| 392 | |
|---|
| 393 | |
|---|
| 394 | def random_element(self, degree=2, terms=5, *args, **kwds): |
|---|
| 395 | r""" |
|---|
| 396 | Return a random polynomial in this polynomial ring. |
|---|
| 397 | |
|---|
| 398 | INPUT: |
|---|
| 399 | degree -- maximum total degree of resulting polynomial |
|---|
| 400 | terms -- maximum number of terms to generate |
|---|
| 401 | |
|---|
| 402 | OUTPUT: a random polynomial of total degree \code{degree} |
|---|
| 403 | and with \code{term} terms in it. |
|---|
| 404 | |
|---|
| 405 | EXAMPLES: |
|---|
| 406 | sage: [QQ['x,y'].random_element() for _ in range(5)] |
|---|
| 407 | [-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] |
|---|
| 408 | sage: R = MPolynomialRing(ZZ, 'x,y',2 ); |
|---|
| 409 | sage: R.random_element(2) # random |
|---|
| 410 | -1*x*y + x + 15*y - 2 |
|---|
| 411 | sage: R.random_element(12) # random |
|---|
| 412 | x^4*y^5 + x^3*y^5 + 6*x^2*y^2 - x^2 |
|---|
| 413 | sage: R.random_element(12,3) # random |
|---|
| 414 | -3*x^4*y^2 - x^5 - x^4*y |
|---|
| 415 | sage: R.random_element(3) # random |
|---|
| 416 | 2*y*z + 2*x + 2*y |
|---|
| 417 | |
|---|
| 418 | sage: R.<x,y> = MPolynomialRing(RR) |
|---|
| 419 | sage: R.random_element(2) # random |
|---|
| 420 | -0.645358174399450*x*y + 0.572655401740132*x + 0.197478565033010 |
|---|
| 421 | |
|---|
| 422 | sage: R.random_element(41) # random |
|---|
| 423 | -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 |
|---|
| 424 | |
|---|
| 425 | AUTHOR: |
|---|
| 426 | -- didier deshommes |
|---|
| 427 | """ |
|---|
| 428 | # General strategy: |
|---|
| 429 | # generate n-tuples of numbers with each element in the tuple |
|---|
| 430 | # not greater than (degree/n) so that the degree |
|---|
| 431 | # (ie, the sum of the elements in the tuple) does not exceed |
|---|
| 432 | # their total degree |
|---|
| 433 | |
|---|
| 434 | n = self.__ngens # length of the n-tuple |
|---|
| 435 | max_deg = int(degree/n) # max degree for each term |
|---|
| 436 | R = self.base_ring() |
|---|
| 437 | |
|---|
| 438 | # restrict exponents to positive integers only |
|---|
| 439 | exponents = [ tuple([ZZ.random_element(0,max_deg+1) for _ in range(n)]) |
|---|
| 440 | for _ in range(terms) ] |
|---|
| 441 | coeffs = [] |
|---|
| 442 | for _ in range(terms): |
|---|
| 443 | c = R.random_element(*args,**kwds) |
|---|
| 444 | while not c: |
|---|
| 445 | c = R.random_element(*args,**kwds) |
|---|
| 446 | coeffs.append(c) # allow only nonzero coefficients |
|---|
| 447 | |
|---|
| 448 | d = dict( zip(tuple(exponents), coeffs) ) |
|---|
| 449 | return self(multi_polynomial_element.MPolynomial_polydict(self, PolyDict(d))) |
|---|
| 450 | |
|---|
| 451 | |
|---|
| 452 | #################### |
|---|
| 453 | # Leave *all* old versions! |
|---|
| 454 | |
|---|
| 455 | def unpickle_MPolynomialRing_generic_v1(base_ring, n, names, order): |
|---|
| 456 | from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing |
|---|
| 457 | return MPolynomialRing(base_ring, n, names=names, order=order) |
|---|
| 458 | |
|---|
| 459 | |
|---|
| 460 | def unpickle_MPolynomialRing_generic(base_ring, n, names, order): |
|---|
| 461 | from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing |
|---|
| 462 | |
|---|
| 463 | return MPolynomialRing(base_ring, n, names=names, order=order) |
|---|