Ticket #1046: 1046-mpoly-coerce-speed.patch
| File 1046-mpoly-coerce-speed.patch, 20.2 kB (added by robertwb, 3 months ago) |
|---|
-
a/sage/categories/pushout.py
old new 4 4 # TODO, think through the rankings, and override pushout where necessary. 5 5 6 6 class ConstructionFunctor(Functor): 7 7 8 def __mul__(self, other): 8 9 if not isinstance(self, ConstructionFunctor) and not isinstance(other, ConstructionFunctor): 9 10 raise TypeError, "Non-constructive product" … … 38 39 39 40 def commutes(self, other): 40 41 return False 42 43 def expand(self): 44 return [self] 45 41 46 42 class CompositeConstructionFunctor(ConstructionFunctor): 43 def __init__(self, first, second): 44 Functor.__init__(self, first.domain(), second.codomain()) 45 self._first = first 46 self._second = second 47 class CompositConstructionFunctor(ConstructionFunctor): 48 49 def __init__(self, *args): 50 self.all = [] 51 for c in args: 52 if isinstance(c, list): 53 self.all += c 54 elif isinstance(c, CompositConstructionFunctor): 55 self.all += c.all 56 else: 57 self.all.append(c) 58 Functor.__init__(self, self.all[0].domain(), self.all[-1].codomain()) 47 59 48 60 def __call__(self, R): 49 return self._second(self._first(R)) 61 for c in self.all: 62 R = c(R) 63 return R 50 64 51 65 def __cmp__(self, other): 52 c = cmp(self._first, other._first) 53 if c == 0: 54 c = cmp(self._second, other._second) 55 return c 66 if isinstance(other, CompositConstructionFunctor): 67 return cmp(self.all, other.all) 68 else: 69 return cmp(type(self), type(other)) 70 71 def __mul__(self, other): 72 if isinstance(self, CompositConstructionFunctor): 73 all = self.all + [other] 74 else: 75 all = [self] + other.all 76 return CompositConstructionFunctor(*all) 56 77 57 78 def __str__(self): 58 return "%s(%s)" % (self._second, self._first) 79 s = "..." 80 for c in self.all: 81 s = "%s(%s)" % (c,s) 82 return s 83 84 def expand(self): 85 return self.all 86 59 87 60 88 class IdentityConstructionFunctor(ConstructionFunctor): 89 90 rank = -100 91 61 92 def __init__(self): 62 93 Functor.__init__(self, Sets(), Sets()) 63 self.rank = -10064 94 def __call__(self, R): 65 95 return R 66 96 def __mul__(self, other): … … 69 99 else: 70 100 return self 71 101 102 103 104 72 105 class PolynomialFunctor(ConstructionFunctor): 106 107 rank = 9 108 73 109 def __init__(self, var, multi_variate=False): 74 110 Functor.__init__(self, Rings(), Rings()) 75 111 self.var = var 76 112 self.multi_variate = multi_variate 77 self.rank = 9 113 78 114 def __call__(self, R): 79 115 from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing 80 from sage.rings.polynomial.polynomial_ring import is_PolynomialRing 81 from sage.rings.polynomial.multi_polynomial_ring_generic import is_MPolynomialRing 82 if self.multi_variate and (is_MPolynomialRing(R) or is_PolynomialRing(R)): 83 return PolynomialRing(R.base_ring(), (list(R.variable_names()) + [self.var])) 84 else: 85 return PolynomialRing(R, self.var) 116 return PolynomialRing(R, self.var) 117 86 118 def __cmp__(self, other): 87 119 c = cmp(type(self), type(other)) 88 120 if c == 0: 89 121 c = cmp(self.var, other.var) 122 elif isinstance(other, MultiPolynomialFunctor): 123 return -cmp(other, self) 90 124 return c 125 91 126 def merge(self, other): 92 if self == other: 93 return PolynomialFunctor(self.var, (self.multi_variate or other.multi_variate)) 94 elif isinstance(other, LaurentPolynomialFunctor) and self.var == other.var: 95 return LaurentPolynomialFunctor(self.var, (self.multi_variate or other.multi_variate)) 96 127 if isinstance(other, MultiPolynomialFunctor): 128 return other.merge(self) 129 elif self == other: 130 return self 97 131 else: 98 132 return None 99 # def __str__(self): 100 # return "Poly(%s)" % self.var 133 134 def __str__(self): 135 return "Poly[%s]" % self.var 136 137 class MultiPolynomialFunctor(ConstructionFunctor): 138 """ 139 A constructor for multivariate polynomial rings. 140 """ 141 142 rank = 9 143 144 def __init__(self, vars, term_order): 145 """ 146 EXAMPLES: 147 sage: F = sage.categories.pushout.MultiPolynomialFunctor(['x','y'], None) 148 sage: F 149 MPoly[x,y] 150 sage: F(ZZ) 151 Multivariate Polynomial Ring in x, y over Integer Ring 152 sage: F(CC) 153 Multivariate Polynomial Ring in x, y over Complex Field with 53 bits of precision 154 """ 155 Functor.__init__(self, Rings(), Rings()) 156 self.vars = vars 157 self.term_order = term_order 158 159 def __call__(self, R): 160 """ 161 EXAMPLES: 162 sage: R.<x,y,z> = QQ[] 163 sage: F = R.construction()[0]; F 164 MPoly[x,y,z] 165 sage: type(F) 166 <class 'sage.categories.pushout.MultiPolynomialFunctor'> 167 sage: F(ZZ) 168 Multivariate Polynomial Ring in x, y, z over Integer Ring 169 sage: F(RR) 170 Multivariate Polynomial Ring in x, y, z over Real Field with 53 bits of precision 171 """ 172 from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing 173 return PolynomialRing(R, self.vars) 174 175 def __cmp__(self, other): 176 """ 177 EXAMPLES: 178 sage: F = ZZ['x,y,z'].construction()[0] 179 sage: G = QQ['x,y,z'].construction()[0] 180 sage: F == G 181 True 182 sage: G = ZZ['x,y'].construction()[0] 183 sage: F == G 184 False 185 """ 186 c = cmp(type(self), type(other)) 187 if c == 0: 188 c = cmp(self.vars, other.vars) or cmp(self.term_order, other.term_order) 189 elif isinstance(other, PolynomialFunctor): 190 c = cmp(self.vars, (other.var,)) 191 return c 192 193 def __mul__(self, other): 194 """ 195 If two MPoly functors are given in a row, form a single MPoly functor 196 with all of the variables. 197 198 EXAMPLES: 199 sage: F = sage.categories.pushout.MultiPolynomialFunctor(['x','y'], None) 200 sage: G = sage.categories.pushout.MultiPolynomialFunctor(['t'], None) 201 sage: G*F 202 MPoly[x,y,t] 203 """ 204 if isinstance(other, MultiPolynomialFunctor): 205 if self.term_order != other.term_order: 206 raise TypeError, "Incompatible term orders (%s,%s)." % (self.term_order, other.term_order) 207 if set(self.vars).intersection(other.vars): 208 raise TypeError, "Overlaping variables (%s,%s)" % (self.vars, other.vars) 209 return MultiPolynomialFunctor(other.vars + self.vars, self.term_order) 210 elif isinstance(other, CompositConstructionFunctor) \ 211 and isinstance(other.all[-1], MultiPolynomialFunctor): 212 return CompositConstructionFunctor(other.all[:-1], self * other.all[-1]) 213 else: 214 return CompositConstructionFunctor(other, self) 215 216 def merge(self, other): 217 """ 218 EXAMPLES: 219 sage: F = sage.categories.pushout.MultiPolynomialFunctor(['x','y'], None) 220 sage: G = sage.categories.pushout.MultiPolynomialFunctor(['t'], None) 221 sage: F.merge(G) is None 222 True 223 sage: F.merge(F) 224 MPoly[x,y] 225 """ 226 if self == other: 227 return self 228 else: 229 return None 230 231 def expand(self): 232 """ 233 EXAMPLES: 234 sage: F = QQ['x,y,z,t'].construction()[0]; F 235 MPoly[x,y,z,t] 236 sage: F.expand() 237 [MPoly[t], MPoly[z], MPoly[y], MPoly[x]] 238 239 Now an actual use case: 240 sage: R.<x,y,z> = ZZ[] 241 sage: S.<z,t> = QQ[] 242 sage: x+t 243 x + t 244 sage: parent(x+t) 245 Multivariate Polynomial Ring in x, y, z, t over Rational Field 246 sage: T.<y,s> = QQ[] 247 sage: x + s 248 Traceback (most recent call last): 249 ... 250 TypeError: unsupported operand parent(s) for '+': 'Multivariate Polynomial Ring in x, y, z over Integer Ring' and 'Multivariate Polynomial Ring in y, s over Rational Field' 251 sage: R = PolynomialRing(ZZ, 'x', 500) 252 sage: S = PolynomialRing(GF(5), 'x', 200) 253 sage: R.gen(0) + S.gen(0) 254 2*x0 255 """ 256 if len(self.vars) <= 1: 257 return [self] 258 else: 259 return [MultiPolynomialFunctor((x,), self.term_order) for x in reversed(self.vars)] 260 261 def __str__(self): 262 """ 263 EXAMPLES: 264 sage: QQ['x,y,z,t'].construction()[0] 265 MPoly[x,y,z,t] 266 """ 267 return "MPoly[%s]" % ','.join(self.vars) 268 101 269 102 270 class MatrixFunctor(ConstructionFunctor): 271 272 rank = 10 273 103 274 def __init__(self, nrows, ncols, is_sparse=False): 104 275 # if nrows == ncols: 105 276 # Functor.__init__(self, Rings(), RingModules()) # takes a basering … … 109 280 self.nrows = nrows 110 281 self.ncols = ncols 111 282 self.is_sparse = is_sparse 112 self.rank = 10113 283 def __call__(self, R): 114 284 from sage.matrix.matrix_space import MatrixSpace 115 285 return MatrixSpace(R, self.nrows, self.ncols, sparse=self.is_sparse) … … 125 295 return MatrixFunctor(self.nrows, self.ncols, self.is_sparse and other.is_sparse) 126 296 127 297 class LaurentPolynomialFunctor(ConstructionFunctor): 298 299 rank = 9 300 128 301 def __init__(self, var, multi_variate=False): 129 302 Functor.__init__(self, Rings(), Rings()) 130 303 self.var = var 131 304 self.multi_variate = multi_variate 132 self.rank = 9133 305 def __call__(self, R): 134 306 from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing, is_LaurentPolynomialRing 135 307 if self.multi_variate and is_LaurentPolynomialRing(R): … … 149 321 150 322 151 323 class VectorFunctor(ConstructionFunctor): 324 325 rank = 10 # ranking of functor, not rank of module 326 152 327 def __init__(self, n, is_sparse=False, inner_product_matrix=None): 153 328 # if nrows == ncols: 154 329 # Functor.__init__(self, Rings(), RingModules()) # takes a basering … … 158 333 self.n = n 159 334 self.is_sparse = is_sparse 160 335 self.inner_product_matrix = inner_product_matrix 161 self.rank = 10 # ranking of functor, not rank of module162 336 def __call__(self, R): 163 337 from sage.modules.free_module import FreeModule 164 338 return FreeModule(R, self.n, sparse=self.is_sparse, inner_product_matrix=self.inner_product_matrix) … … 172 346 return None 173 347 else: 174 348 return VectorFunctor(self.n, self.is_sparse and other.is_sparse) 175 349 350 176 351 class SubspaceFunctor(ConstructionFunctor): 352 rank = 11 # ranking of functor, not rank of module 177 353 def __init__(self, basis): 178 354 self.basis = basis 179 self.rank = 11 # ranking of functor, not rank of module180 355 def __call__(self, ambient): 181 356 return ambient.span_of_basis(self.basis) 182 357 def __cmp__(self, other): … … 192 367 193 368 194 369 class FractionField(ConstructionFunctor): 370 371 rank = 5 372 195 373 def __init__(self): 196 374 Functor.__init__(self, Rings(), Fields()) 197 self.rank = 5198 375 def __call__(self, R): 199 376 return R.fraction_field() 200 377 378 201 379 class LocalizationFunctor(ConstructionFunctor): 380 381 rank = 6 382 202 383 def __init__(self, t): 203 384 Functor.__init__(self, Rings(), Rings()) 204 385 self.t = t 205 self.rank = 6206 386 def __call__(self, R): 207 387 return R.localize(t) 208 388 def __cmp__(self, other): … … 210 390 if c == 0: 211 391 c = cmp(self.t, other.t) 212 392 return c 213 393 394 214 395 class CompletionFunctor(ConstructionFunctor): 396 397 rank = 4 398 215 399 def __init__(self, p, prec, extras=None): 216 400 Functor.__init__(self, Rings(), Rings()) 217 401 self.p = p 218 402 self.prec = prec 219 403 self.extras = extras 220 self.rank = 4221 404 def __call__(self, R): 222 405 return R.completion(self.p, self.prec, self.extras) 223 406 def __cmp__(self, other): … … 237 420 return other 238 421 else: 239 422 return None 240 423 424 241 425 class QuotientFunctor(ConstructionFunctor): 242 def __init__(self, I): 426 427 rank = 7 428 429 def __init__(self, I, as_field=False): 243 430 Functor.__init__(self, Rings(), Rings()) # much more general... 244 431 self.I = I 245 self. rank = 7432 self.as_field = as_field 246 433 def __call__(self, R): 247 434 I = self.I 248 435 if I.ring() != R: 249 436 I.base_extend(R) 250 return R.quo(I) 437 Q = R.quo(I) 438 if self.as_field and hasattr(Q, 'field'): 439 Q = Q.field() 440 return Q 251 441 def __cmp__(self, other): 252 442 c = cmp(type(self), type(other)) 253 443 if c == 0: … … 266 456 # TODO: Perhaps this should be detected at a higher level... 267 457 raise TypeError, "Trivial quotient intersection." 268 458 return QuotientFunctor(gcd) 459 269 460 270 461 class AlgebraicExtensionFunctor(ConstructionFunctor): 271 462 … … 287 478 c = cmp(self.embedding, other.embedding) 288 479 return c 289 480 481 290 482 class AlgebraicClosureFunctor(ConstructionFunctor): 291 483 292 484 rank = 3 … … 298 490 def merge(self, other): 299 491 # Algebraic Closure subsumes Algebraic Extension 300 492 return self 493 301 494 302 495 def BlackBoxConstructionFunctor(ConstructionFunctor): 496 497 rank = 100 498 303 499 def __init__(self, box): 500 if not callable(box): 501 raise TypeError, "input must be callable" 304 502 self.box = box 305 self.rank = 100306 503 def __call__(self, R): 307 504 return box(R) 308 505 def __cmp__(self, other): … … 435 632 Rc = [c[0] for c in R_tower[1:len(Rs)+1]] 436 633 Sc = [c[0] for c in S_tower[1:len(Ss)+1]] 437 634 635 Rc = sum([c.expand() for c in Rc], []) 636 Sc = sum([c.expand() for c in Sc], []) 637 638 all = IdentityConstructionFunctor() 639 438 640 while len(Rc) > 0 or len(Sc) > 0: 439 641 # print Z 440 642 # if we are out of functors in either tower, there is no ambiguity 441 643 if len(Sc) == 0: 442 c = Rc.pop() 443 Z = c(Z) 644 all = Rc.pop() * all 444 645 elif len(Rc) == 0: 445 c = Sc.pop() 446 Z = c(Z) 646 all = Sc.pop() * all 447 647 # if one of the functors has lower rank, do it first 448 648 elif Rc[-1].rank < Sc[-1].rank: 449 c = Rc.pop() 450 Z = c(Z) 649 all = Rc.pop() * all 451 650 elif Sc[-1].rank < Rc[-1].rank: 452 c = Sc.pop() 453 Z = c(Z) 651 all = Sc.pop() * all 454 652 else: 455 653 # the ranks are the same, so things are a bit subtler 456 654 if Rc[-1] == Sc[-1]: … … 461 659 cS = Sc.pop() 462 660 c = cR.merge(cS) or cS.merge(cR) 463 661 if c: 464 Z = c(Z)662 all = c * all 465 663 else: 466 664 raise TypeError, "Incompatable Base Extension %r, %r (on %r, %r)" % (R, S, cR, cS) 467 665 else: … … 473 671 if Sc[-1] in Rc: 474 672 raise TypeError, "Ambiguous Base Extension" 475 673 else: 476 c = Sc.pop() 477 Z = c(Z) 674 all = Sc.pop() * all 478 675 elif Sc[-1] in Rc: 479 c = Rc.pop(); 480 Z = c(Z) 676 all = Rc.pop() * all 481 677 # If, perchance, the two functors commute, then we may do them in any order. 482 678 elif Rc[-1].commutes(Sc[-1]): 483 c = Rc.pop() 484 Z = c(Z) 485 c = Sc.pop() 486 Z = c(Z) 679 all = Sc.pop() * Rc.pop() * all 487 680 else: 488 681 # try and merge (default merge is failure for unequal functors) 489 682 cR = Rc.pop() 490 683 cS = Sc.pop() 491 684 c = cR.merge(cS) or cS.merge(cR) 492 685 if c is not None: 493 Z = c(Z)686 all = c * all 494 687 else: 495 688 # Otherwise, we cannot proceed. 496 689 raise TypeError, "Ambiguous Base Extension" 497 return Z 690 691 return all(Z) 498 692 499 693 500 694 -
a/sage/rings/polynomial/multi_polynomial_ring_generic.pyx
old new 68 68 """ 69 69 Returns a functor F and basering R such that F(R) == self. 70 70 71 In the multi-variate case, R is a polynomial ring with one72 less variable, and F knows to adjoin the variable in the73 correct way.74 75 71 EXAMPLES: 76 72 sage: S = ZZ['x,y'] 77 73 sage: F, R = S.construction(); R 78 Univariate Polynomial Ring in x over Integer Ring 74 Integer Ring 75 sage: F 76 MPoly[x,y] 79 77 sage: F(R) == S 80 78 True 81 79 sage: F(R) == ZZ['x']['y'] … … 83 81 84 82 """ 85 83 from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing 86 from sage.categories.pushout import PolynomialFunctor 87 vars = self.variable_names() 88 if len(vars) == 1: 89 return PolynomialFunctor(vars[0], False), self.base_ring() 90 else: 91 return PolynomialFunctor(vars[-1], True), PolynomialRing(self.base_ring(), vars[:-1]) 84 from sage.categories.pushout import MultiPolynomialFunctor 85 return MultiPolynomialFunctor(self.variable_names(), self.term_order()), self.base_ring() 92 86 93 87 def completion(self, p, prec=20, extras=None): 94 88 try: -
a/sage/rings/quotient_ring.py
old new 207 207 sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) 208 208 sage: R.quotient_ring(I).construction() 209 209 (QuotientFunctor, Univariate Polynomial Ring in x over Integer Ring) 210 211 TESTS: 212 sage: F, R = Integers(5).construction() 213 sage: F(R) 214 Ring of integers modulo 5 215 sage: F, R = GF(5).construction() 216 sage: F(R) 217 Finite Field of size 5 210 218 """ 211 219 from sage.categories.pushout import QuotientFunctor 212 return QuotientFunctor(self.__I), self.__R 220 # Is there a better generic way to distinguish between things like Z/pZ as a field and Z/pZ as a ring? 221 from sage.rings.field import Field 222 return QuotientFunctor(self.__I, as_field=isinstance(self, Field)), self.__R 213 223 214 224 def _repr_(self): 215 225 """ -
a/sage/structure/coerce.pyx
old new 1025 1025 Z = pushout(R, S) 1026 1026 coerce_R = Z.coerce_map_from(R) 1027 1027 coerce_S = Z.coerce_map_from(S) 1028 if coerce_R is not None and coerce_S is not None: 1029 return coerce_R, coerce_S 1028 if coerce_R is None: 1029 raise TypeError, "No coercion from %s to pushout %s" % (R, Z) 1030 if coerce_S is None: 1031 raise TypeError, "No coercion from %s to pushout %s" % (S, Z) 1032 return coerce_R, coerce_S 1030 1033 except: 1031 1034 self._record_exception() 1032 1035