Ticket #7797: trac7797-full_letterplace_wrapper_combined.patch
| File trac7797-full_letterplace_wrapper_combined.patch, 117.6 KB (added by SimonKing, 6 months ago) |
|---|
-
doc/en/reference/algebras.rst
# HG changeset patch # User Simon King <simon.king@uni-jena.de> # Date 1301320222 -7200 # Node ID b386895e038bfb07e5acf4658eabc61258b98d0b # Parent a837878923f7fcf4745cb616b3e35cd3e57a6569 #7797: A full wrapper for Singular's letterplace, rel #12988 An alternative implementation of free algebras (faster arithmetic), introducing a UniqueFactory for free algebras. Degree-wise Groebner bases for twosided weighted homogeneous ideals in free algebras. Complete Groebner bases for weighted homogeneous twosided ideals of free algebras, provided they exist. diff --git a/doc/en/reference/algebras.rst b/doc/en/reference/algebras.rst
a b 9 9 sage/algebras/free_algebra 10 10 sage/algebras/free_algebra_element 11 11 12 sage/algebras/letterplace/free_algebra_letterplace 13 sage/algebras/letterplace/free_algebra_element_letterplace 14 sage/algebras/letterplace/letterplace_ideal 15 12 16 sage/algebras/free_algebra_quotient 13 17 sage/algebras/free_algebra_quotient_element 14 18 -
module_list.py
diff --git a/module_list.py b/module_list.py
a b 114 114 include_dirs = [SAGE_INC + 'FLINT/'], 115 115 depends = flint_depends), 116 116 117 Extension('sage.algebras.letterplace.free_algebra_letterplace', 118 sources = ['sage/algebras/letterplace/free_algebra_letterplace.pyx'], 119 language="c++", 120 include_dirs = [SAGE_INC +'singular/'], 121 depends = singular_depends), 122 123 Extension('sage.algebras.letterplace.free_algebra_element_letterplace', 124 sources = ['sage/algebras/letterplace/free_algebra_element_letterplace.pyx'], 125 language="c++", 126 include_dirs = [SAGE_INC +'singular/'], 127 depends = singular_depends), 128 129 Extension('sage.algebras.letterplace.letterplace_ideal', 130 sources = ['sage/algebras/letterplace/letterplace_ideal.pyx'], 131 language="c++", 132 include_dirs = [SAGE_INC +'singular/'], 133 depends = singular_depends), 134 117 135 Extension('sage.algebras.quatalg.quaternion_algebra_cython', 118 136 sources = ['sage/algebras/quatalg/quaternion_algebra_cython.pyx'], 119 137 language='c++', -
sage/algebras/free_algebra.py
diff --git a/sage/algebras/free_algebra.py b/sage/algebras/free_algebra.py
a b 9 9 things. 10 10 11 11 - Simon King (2011-04): Put free algebras into the category framework. 12 Reimplement free algebra constructor, using a 13 :class:`~sage.structure.factory.UniqueFactory` for handling 14 different implementations of free algebras. Allow degree weights 15 for free algebras in letterplace implementation. 12 16 13 17 EXAMPLES:: 14 18 … … 20 24 sage: G.base_ring() 21 25 Free Algebra on 3 generators (x, y, z) over Integer Ring 22 26 27 The above free algebra is based on a generic implementation. By 28 :trac:`7797`, there is a different implementation 29 :class:`~sage.algebras.letterplace.free_algebra_letterplace.FreeAlgebra_letterplace` 30 based on Singular's letterplace rings. It is currently restricted to 31 weighted homogeneous elements and is therefore not the default. But the 32 arithmetic is much faster than in the generic implementation. 33 Moreover, we can compute Groebner bases with degree bound for its 34 two-sided ideals, and thus provide ideal containment tests:: 35 36 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 37 sage: F 38 Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 39 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 40 sage: I.groebner_basis(degbound=4) 41 Twosided Ideal (y*z*y*y - y*z*y*z + y*z*z*y - y*z*z*z, y*z*y*x + y*z*y*z + y*z*z*x + y*z*z*z, y*y*z*y - y*y*z*z + y*z*z*y - y*z*z*z, y*y*z*x + y*y*z*z + y*z*z*x + y*z*z*z, y*y*y - y*y*z + y*z*y - y*z*z, y*y*x + y*y*z + y*z*x + y*z*z, x*y + y*z, x*x - y*x - y*y - y*z) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 42 sage: y*z*y*y*z*z + 2*y*z*y*z*z*x + y*z*y*z*z*z - y*z*z*y*z*x + y*z*z*z*z*x in I 43 True 44 45 Positive integral degree weights for the letterplace implementation 46 was introduced in trac ticket #...:: 47 48 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) 49 sage: x.degree() 50 2 51 sage: y.degree() 52 1 53 sage: z.degree() 54 3 55 sage: I = F*[x*y-y*x, x^2+2*y*z, (x*y)^2-z^2]*F 56 sage: Q.<a,b,c> = F.quo(I) 57 sage: TestSuite(Q).run() 58 sage: a^2*b^2 59 c*c 60 23 61 TESTS:: 24 62 25 63 sage: F = FreeAlgebra(GF(5),3,'x') 26 64 sage: TestSuite(F).run() 65 sage: F is loads(dumps(F)) 66 True 67 sage: F = FreeAlgebra(GF(5),3,'x', implementation='letterplace') 68 sage: TestSuite(F).run() 69 sage: F is loads(dumps(F)) 70 True 27 71 28 72 :: 29 73 30 74 sage: F.<x,y,z> = FreeAlgebra(GF(5),3) 31 75 sage: TestSuite(F).run() 76 sage: F is loads(dumps(F)) 77 True 78 sage: F.<x,y,z> = FreeAlgebra(GF(5),3, implementation='letterplace') 79 sage: TestSuite(F).run() 80 sage: F is loads(dumps(F)) 81 True 32 82 33 83 :: 34 84 35 85 sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y']) 36 86 sage: TestSuite(F).run() 87 sage: F is loads(dumps(F)) 88 True 89 sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y'], implementation='letterplace') 90 sage: TestSuite(F).run() 91 sage: F is loads(dumps(F)) 92 True 37 93 38 94 :: 39 95 40 96 sage: F = FreeAlgebra(GF(5),3, 'abc') 41 97 sage: TestSuite(F).run() 98 sage: F is loads(dumps(F)) 99 True 100 sage: F = FreeAlgebra(GF(5),3, 'abc', implementation='letterplace') 101 sage: TestSuite(F).run() 102 sage: F is loads(dumps(F)) 103 True 42 104 43 105 :: 44 106 45 sage: F = FreeAlgebra(FreeAlgebra(ZZ, 1,'a'), 2, 'x')107 sage: F = FreeAlgebra(FreeAlgebra(ZZ,2,'ab'), 2, 'x') 46 108 sage: TestSuite(F).run() 109 sage: F is loads(dumps(F)) 110 True 111 112 Note that the letterplace implementation can only be used if the corresponding 113 (multivariate) polynomial ring has an implementation in Singular:: 114 115 sage: FreeAlgebra(FreeAlgebra(ZZ,2,'ab'), 2, 'x', implementation='letterplace') 116 Traceback (most recent call last): 117 ... 118 NotImplementedError: The letterplace implementation is not available for the free algebra you requested 47 119 48 120 """ 49 121 … … 66 138 67 139 import sage.structure.parent_gens 68 140 69 def FreeAlgebra(R, n, names): 141 from sage.structure.factory import UniqueFactory 142 from sage.all import PolynomialRing 143 from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular 144 145 class FreeAlgebraFactory(UniqueFactory): 70 146 """ 71 Return the free algebra over the ring `R` on `n` 72 generators with given names. 73 74 INPUT: 75 76 - ``R`` - ring 77 - ``n`` - integer 78 - ``names`` - string or list/tuple of n strings 79 80 OUTPUT: 81 82 A free algebra. 83 147 A constructor of free algebras. 148 149 See :mod:`~sage.algebras.free_algebra` for examples and corner cases. 150 84 151 EXAMPLES:: 85 152 86 153 sage: FreeAlgebra(GF(5),3,'x') 87 154 Free Algebra on 3 generators (x0, x1, x2) over Finite Field of size 5 88 155 sage: F.<x,y,z> = FreeAlgebra(GF(5),3) … … 105 172 sage: G = FreeAlgebra(ZZ,3,'x,y,z') 106 173 sage: F is G 107 174 True 175 sage: F.<x,y,z> = FreeAlgebra(GF(5),3) # indirect doctest 176 sage: F is loads(dumps(F)) 177 True 178 sage: F is FreeAlgebra(GF(5),['x','y','z']) 179 True 180 sage: copy(F) is F is loads(dumps(F)) 181 True 182 sage: TestSuite(F).run() 183 184 By :trac:`7797`, we provide a different implementation of free 185 algebras, based on Singular's "letterplace rings". Our letterplace 186 wrapper allows for chosing positive integral degree weights for the 187 generators of the free algebra. However, only (weighted) homogenous 188 elements are supported. Of course, isomorphic algebras in different 189 implementations are not identical:: 190 191 sage: G = FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace') 192 sage: F == G 193 False 194 sage: G is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace') 195 True 196 sage: copy(G) is G is loads(dumps(G)) 197 True 198 sage: TestSuite(G).run() 199 200 :: 201 202 sage: H = FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace', degrees=[1,2,3]) 203 sage: F != H != G 204 True 205 sage: H is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace', degrees=[1,2,3]) 206 True 207 sage: copy(H) is H is loads(dumps(H)) 208 True 209 sage: TestSuite(H).run() 108 210 109 211 Free algebras commute with their base ring. 110 212 :: … … 122 224 sage: c^3 * a * b^2 123 225 a*b^2*c^3 124 226 """ 125 names = sage.structure.parent_gens.normalize_names(n, names) 126 return cache(R, n, names) 227 def create_key(self,base_ring, arg1=None, arg2=None, 228 sparse=False, order='degrevlex', 229 names=None, name=None, 230 implementation=None, degrees=None): 231 """ 232 Create the key under which a free algebra is stored. 233 234 TESTS:: 235 236 sage: FreeAlgebra.create_key(GF(5),['x','y','z']) 237 (Finite Field of size 5, ('x', 'y', 'z')) 238 sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3) 239 (Finite Field of size 5, ('x', 'y', 'z')) 240 sage: FreeAlgebra.create_key(GF(5),3,'xyz') 241 (Finite Field of size 5, ('x', 'y', 'z')) 242 sage: FreeAlgebra.create_key(GF(5),['x','y','z'], implementation='letterplace') 243 (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,) 244 sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3, implementation='letterplace') 245 (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,) 246 sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace') 247 (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,) 248 sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace', degrees=[1,2,3]) 249 ((1, 2, 3), Multivariate Polynomial Ring in x, y, z, x_ over Finite Field of size 5) 250 251 """ 252 if arg1 is None and arg2 is None and names is None: 253 # this is used for pickling 254 if degrees is None: 255 return (base_ring,) 256 return tuple(degrees),base_ring 257 PolRing = None 258 # test if we can use libSingular/letterplace 259 if implementation is not None and implementation != 'generic': 260 try: 261 PolRing = PolynomialRing(base_ring, arg1, arg2, 262 sparse=sparse, order=order, 263 names=names, name=name, 264 implementation=implementation if implementation!='letterplace' else None) 265 if not isinstance(PolRing,MPolynomialRing_libsingular): 266 if PolRing.ngens() == 1: 267 PolRing = PolynomialRing(base_ring,1,PolRing.variable_names()) 268 if not isinstance(PolRing,MPolynomialRing_libsingular): 269 raise TypeError 270 else: 271 raise TypeError 272 except (TypeError, NotImplementedError),msg: 273 raise NotImplementedError, "The letterplace implementation is not available for the free algebra you requested" 274 if PolRing is not None: 275 if degrees is None: 276 return (PolRing,) 277 from sage.all import TermOrder 278 T = PolRing.term_order()+TermOrder('lex',1) 279 varnames = list(PolRing.variable_names()) 280 newname = 'x' 281 while newname in varnames: 282 newname += '_' 283 varnames.append(newname) 284 return tuple(degrees),PolynomialRing(PolRing.base(), varnames, 285 sparse=sparse, order=T, 286 implementation=implementation if implementation!='letterplace' else None) 287 # normalise the generator names 288 from sage.all import Integer 289 if isinstance(arg1, (int, long, Integer)): 290 arg1, arg2 = arg2, arg1 291 if not names is None: 292 arg1 = names 293 elif not name is None: 294 arg1 = name 295 if arg2 is None: 296 arg2 = len(arg1) 297 names = sage.structure.parent_gens.normalize_names(arg2,arg1) 298 return base_ring, names 299 300 def create_object(self, version, key): 301 """ 302 Construct the free algebra that belongs to a unique key. 303 304 NOTE: 305 306 Of course, that method should not be called directly, 307 since it does not use the cache of free algebras. 308 309 TESTS:: 310 311 sage: FreeAlgebra.create_object('4.7.1', (QQ['x','y'],)) 312 Free Associative Unital Algebra on 2 generators (x, y) over Rational Field 313 sage: FreeAlgebra.create_object('4.7.1', (QQ['x','y'],)) is FreeAlgebra(QQ,['x','y']) 314 False 315 316 """ 317 if len(key)==1: 318 from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace 319 return FreeAlgebra_letterplace(key[0]) 320 if isinstance(key[0],tuple): 321 from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace 322 return FreeAlgebra_letterplace(key[1],degrees=key[0]) 323 return FreeAlgebra_generic(key[0],len(key[1]),key[1]) 324 325 FreeAlgebra = FreeAlgebraFactory('FreeAlgebra') 326 127 327 128 328 def is_FreeAlgebra(x): 129 329 """ … … 138 338 False 139 339 sage: is_FreeAlgebra(FreeAlgebra(ZZ,100,'x')) 140 340 True 341 sage: is_FreeAlgebra(FreeAlgebra(ZZ,10,'x',implementation='letterplace')) 342 True 343 sage: is_FreeAlgebra(FreeAlgebra(ZZ,10,'x',implementation='letterplace', degrees=range(1,11))) 344 True 345 141 346 """ 142 return isinstance(x, FreeAlgebra_generic) 347 from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace 348 return isinstance(x, (FreeAlgebra_generic,FreeAlgebra_letterplace)) 143 349 144 350 145 351 class FreeAlgebra_generic(Algebra): … … 158 364 x*y*x*y*x*y*x*y*x*y*x*y + x*y*z*x*y*z*x*y*z*x*y*z 159 365 sage: (2 + x*z + x^2)^2 + (x - y)^2 160 366 4 + 5*x^2 - x*y + 4*x*z - y*x + y^2 + x^4 + x^3*z + x*z*x^2 + x*z*x*z 367 368 TESTS: 369 370 Free algebras commute with their base ring. 371 :: 372 373 sage: K.<a,b> = FreeAlgebra(QQ) 374 sage: K.is_commutative() 375 False 376 sage: L.<c,d> = FreeAlgebra(K) 377 sage: L.is_commutative() 378 False 379 sage: s = a*b^2 * c^3; s 380 a*b^2*c^3 381 sage: parent(s) 382 Free Algebra on 2 generators (c, d) over Free Algebra on 2 generators (a, b) over Rational Field 383 sage: c^3 * a * b^2 384 a*b^2*c^3 385 161 386 """ 162 387 Element = FreeAlgebraElement 163 388 def __init__(self, R, n, names): … … 174 399 175 400 sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctet 176 401 Free Algebra on 3 generators (x, y, z) over Rational Field 402 403 TEST: 404 405 Note that the following is *not* the recommended way to create 406 a free algebra. 407 :: 408 409 sage: from sage.algebras.free_algebra import FreeAlgebra_generic 410 sage: FreeAlgebra_generic(ZZ,3,'abc') 411 Free Algebra on 3 generators (a, b, c) over Integer Ring 412 177 413 """ 178 414 if not isinstance(R, Ring): 179 415 raise TypeError("Argument R must be a ring.") … … 218 454 def __cmp__(self, other): 219 455 """ 220 456 Two free algebras are considered the same if they have the same 221 base ring, number of generators and variable names. 457 base ring, number of generators and variable names, and the same 458 implementation. 222 459 223 460 EXAMPLES:: 224 461 … … 233 470 False 234 471 sage: F == FreeAlgebra(QQ,3,'y') 235 472 False 473 474 Note that since :trac:`7797` there is a different 475 implementation of free algebras. Two corresponding free 476 algebras in different implementations are not equal, but there 477 is a coercion:: 478 479 236 480 """ 237 481 if not isinstance(other, FreeAlgebra_generic): 238 482 return -1 239 483 c = cmp(self.base_ring(), other.base_ring()) 240 484 if c: return c 241 c = cmp(self.__ngens, other. __ngens)485 c = cmp(self.__ngens, other.ngens()) 242 486 if c: return c 243 487 c = cmp(self.variable_names(), other.variable_names()) 244 488 if c: return c … … 251 495 EXAMPLES:: 252 496 253 497 sage: F = FreeAlgebra(QQ,3,'x') 254 sage: printF # indirect doctest498 sage: F # indirect doctest 255 499 Free Algebra on 3 generators (x0, x1, x2) over Rational Field 256 500 sage: F.rename('QQ<<x0,x1,x2>>') 257 sage: printF #indirect doctest501 sage: F #indirect doctest 258 502 QQ<<x0,x1,x2>> 259 503 sage: FreeAlgebra(ZZ,1,['a']) 260 504 Free Algebra on 1 generators (a,) over Integer Ring … … 264 508 265 509 def _element_constructor_(self, x): 266 510 """ 267 Co ercex into self.511 Convert x into self. 268 512 269 513 EXAMPLES:: 270 514 271 515 sage: R.<x,y> = FreeAlgebra(QQ,2) 272 516 sage: R(3) # indirect doctest 273 517 3 518 519 TESTS:: 520 521 sage: F.<x,y,z> = FreeAlgebra(GF(5),3) 522 sage: L.<x,y,z> = FreeAlgebra(ZZ,3,implementation='letterplace') 523 sage: F(x) # indirect doctest 524 x 525 sage: F.1*L.2 526 y*z 527 sage: (F.1*L.2).parent() is F 528 True 529 530 :: 531 532 sage: K.<z> = GF(25) 533 sage: F.<a,b,c> = FreeAlgebra(K,3) 534 sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace') 535 sage: F.1+(z+1)*L.2 536 b + (z+1)*c 537 274 538 """ 275 539 if isinstance(x, FreeAlgebraElement): 276 540 P = x.parent() … … 278 542 return x 279 543 if not (P is self.base_ring()): 280 544 return self.element_class(self, x) 545 elif hasattr(x,'letterplace_polynomial'): 546 P = x.parent() 547 if self.has_coerce_map_from(P): # letterplace versus generic 548 ngens = P.ngens() 549 M = self.__monoid 550 def exp_to_monomial(T): 551 out = [] 552 for i in xrange(len(T)): 553 if T[i]: 554 out.append((i%ngens,T[i])) 555 return M(out) 556 return self.element_class(self, dict([(exp_to_monomial(T),c) for T,c in x.letterplace_polynomial().dict().iteritems()])) 281 557 # ok, not a free algebra element (or should not be viewed as one). 558 if isinstance(x, basestring): 559 from sage.all import sage_eval 560 return sage_eval(x,locals=self.gens_dict()) 282 561 F = self.__monoid 283 562 R = self.base_ring() 284 563 # coercion from free monoid … … 299 578 300 579 - this free algebra 301 580 581 - a free algebra in letterplace implementation that has 582 the same generator names and whose base ring coerces 583 into self's base ring 584 302 585 - the underlying monoid 303 586 304 587 - anything that coerces to the base ring of this free algebra … … 366 649 TypeError: no canonical coercion from Free Algebra on 3 generators 367 650 (x, y, z) over Finite Field of size 7 to Free Algebra on 3 368 651 generators (x, y, z) over Integer Ring 652 653 TESTS:: 654 655 sage: F.<x,y,z> = FreeAlgebra(GF(5),3) 656 sage: L.<x,y,z> = FreeAlgebra(GF(5),3,implementation='letterplace') 657 sage: F(x) 658 x 659 sage: F.1*L.2 # indirect doctest 660 y*z 661 369 662 """ 370 663 try: 371 664 R = x.parent() … … 419 712 True 420 713 sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z')) 421 714 False 715 sage: K.<z> = GF(25) 716 sage: F.<a,b,c> = FreeAlgebra(K,3) 717 sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace') 718 sage: F.1+(z+1)*L.2 # indirect doctest 719 b + (z+1)*c 720 422 721 """ 423 722 if self.__monoid.has_coerce_map_from(R): 424 723 return True -
sage/algebras/free_algebra_element.py
diff --git a/sage/algebras/free_algebra_element.py b/sage/algebras/free_algebra_element.py
a b 78 78 EXAMPLES:: 79 79 80 80 sage: A.<x,y,z>=FreeAlgebra(ZZ,3) 81 sage: repr(-x+3*y*z) 81 sage: repr(-x+3*y*z) # indirect doctest 82 82 '-x + 3*y*z' 83 83 84 84 Trac ticket #11068 enables the use of local variable names:: … … 105 105 EXAMPLES:: 106 106 107 107 sage: A.<x,y,z>=FreeAlgebra(ZZ,3) 108 sage: latex(-x+3*y^20*z) 108 sage: latex(-x+3*y^20*z) # indirect doctest 109 109 \left(-1\right)x + 3y^{20}z 110 110 sage: alpha,beta,gamma=FreeAlgebra(ZZ,3,'alpha,beta,gamma').gens() 111 111 sage: latex(alpha-beta) … … 197 197 EXAMPLES:: 198 198 199 199 sage: R.<x,y> = FreeAlgebra(QQ,2) 200 sage: x + y 200 sage: x + y # indirect doctest 201 201 x + y 202 202 """ 203 203 A = self.parent() … … 234 234 EXAMPLES:: 235 235 236 236 sage: R.<x,y> = FreeAlgebra(QQ,2) 237 sage: -(x+y) 237 sage: -(x+y) # indirect doctest 238 238 -x - y 239 239 """ 240 240 y = self.parent()(0) … … 252 252 EXAMPLES:: 253 253 254 254 sage: R.<x,y> = FreeAlgebra(QQ,2) 255 sage: x - y 255 sage: x - y # indirect doctest 256 256 x - y 257 257 """ 258 258 A = self.parent() … … 290 290 EXAMPLES:: 291 291 292 292 sage: A.<x,y,z>=FreeAlgebra(ZZ,3) 293 sage: (x+y+x*y)*(x+y+1) 293 sage: (x+y+x*y)*(x+y+1) # indirect doctest 294 294 x + y + x^2 + 2*x*y + y*x + y^2 + x*y*x + x*y^2 295 295 """ 296 296 A = self.parent() -
sage/algebras/free_algebra_quotient.py
diff --git a/sage/algebras/free_algebra_quotient.py b/sage/algebras/free_algebra_quotient.py
a b 1 1 """ 2 Free algebra quotients 2 Finite dimensional free algebra quotients 3 4 REMARK: 5 6 This implementation only works for finite dimensional quotients, since 7 a list of basis monomials and the multiplication matrices need to be 8 explicitly provided. 9 10 The homogeneous part of a quotient of a free algebra over a field by a 11 finitely generated homogeneous twosided ideal is available in a 12 different implementation. See 13 :mod:`~sage.algebras.letterplace.free_algebra_letterplace` and 14 :mod:`~sage.rings.quotient_ring`. 3 15 4 16 TESTS:: 5 17 -
new file sage/algebras/letterplace/__init__.py
diff --git a/sage/algebras/letterplace/__init__.py b/sage/algebras/letterplace/__init__.py new file mode 100644
- + 1 # tell Python that letterplace exists -
new file sage/algebras/letterplace/free_algebra_element_letterplace.pxd
diff --git a/sage/algebras/letterplace/free_algebra_element_letterplace.pxd b/sage/algebras/letterplace/free_algebra_element_letterplace.pxd new file mode 100644
- + 1 ############################################################################### 2 # 3 # Copyright (C) 2011 Simon King <simon.king@uni-jena.de> 4 # Distributed under the terms of the GNU General Public License (GPL), 5 # version 2 or any later version. The full text of the GPL is available at: 6 # http://www.gnu.org/licenses/ 7 # 8 ############################################################################### 9 10 cdef class FreeAlgebraElement_letterplace 11 12 from sage.structure.element cimport AlgebraElement, ModuleElement, RingElement, Element 13 from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular, MPolynomial_libsingular 14 from sage.algebras.letterplace.free_algebra_letterplace cimport FreeAlgebra_letterplace 15 include "../../ext/stdsage.pxi" 16 17 cdef class FreeAlgebraElement_letterplace(AlgebraElement): 18 cdef MPolynomial_libsingular _poly 19 -
new file sage/algebras/letterplace/free_algebra_element_letterplace.pyx
diff --git a/sage/algebras/letterplace/free_algebra_element_letterplace.pyx b/sage/algebras/letterplace/free_algebra_element_letterplace.pyx new file mode 100644
- + 1 ############################################################################### 2 # 3 # Copyright (C) 2011 Simon King <simon.king@uni-jena.de> 4 # Distributed under the terms of the GNU General Public License (GPL), 5 # version 2 or any later version. The full text of the GPL is available at: 6 # http://www.gnu.org/licenses/ 7 # 8 ############################################################################### 9 10 """ 11 Weighted homogeneous elements of free algebras, in letterplace implementation. 12 13 AUTHOR: 14 15 - Simon King (2011-03-23): Trac ticket :trac:`7797` 16 17 """ 18 19 from sage.libs.singular.function import lib, singular_function 20 from sage.misc.misc import repr_lincomb 21 from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal 22 23 # Define some singular functions 24 lib("freegb.lib") 25 poly_reduce = singular_function("NF") 26 singular_system=singular_function("system") 27 28 ##################### 29 # Free algebra elements 30 cdef class FreeAlgebraElement_letterplace(AlgebraElement): 31 """ 32 Weighted homogeneous elements of a free associative unital algebra (letterplace implementation) 33 34 EXAMPLES:: 35 36 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 37 sage: x+y 38 x + y 39 sage: x*y !=y*x 40 True 41 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 42 sage: (y^3).reduce(I) 43 y*y*y 44 sage: (y^3).normal_form(I) 45 y*y*z - y*z*y + y*z*z 46 47 Here is an example with nontrivial degree weights:: 48 49 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) 50 sage: I = F*[x*y-y*x, x^2+2*y*z, (x*y)^2-z^2]*F 51 sage: x.degree() 52 2 53 sage: y.degree() 54 1 55 sage: z.degree() 56 3 57 sage: (x*y)^3 58 x*y*x*y*x*y 59 sage: ((x*y)^3).normal_form(I) 60 z*z*y*x 61 sage: ((x*y)^3).degree() 62 9 63 64 """ 65 def __init__(self, A, x, check=True): 66 """ 67 INPUT: 68 69 - A free associative unital algebra in letterplace implementation, `A`. 70 - A homogeneous polynomial that can be coerced into the currently 71 used polynomial ring of `A`. 72 - ``check`` (optional bool, default ``True``): Do not attempt the 73 above coercion (for internal use only). 74 75 TEST:: 76 77 sage: from sage.algebras.letterplace.free_algebra_element_letterplace import FreeAlgebraElement_letterplace 78 sage: F.<x,y,z> = FreeAlgebra(GF(3), implementation='letterplace') 79 sage: F.set_degbound(2) 80 sage: P = F.current_ring() 81 sage: F.set_degbound(4) 82 sage: P == F.current_ring() 83 False 84 sage: p = FreeAlgebraElement_letterplace(F,P.1*P.3+2*P.0*P.4); p 85 -x*y + y*x 86 sage: loads(dumps(p)) == p 87 True 88 89 """ 90 cdef FreeAlgebra_letterplace P = A 91 if check: 92 if not x.is_homogeneous(): 93 raise ValueError, "Free algebras based on Letterplace can currently only work with weighted homogeneous elements" 94 P.set_degbound(x.degree()) 95 x = P._current_ring(x) 96 AlgebraElement.__init__(self,P) 97 self._poly = x 98 def __reduce__(self): 99 """ 100 Pickling. 101 102 TEST:: 103 104 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 105 sage: loads(dumps(x*y*x)) == x*y*x # indirect doctest 106 True 107 108 """ 109 return self.__class__, (self._parent,self._poly) 110 def __copy__(self): 111 """ 112 TEST:: 113 114 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 115 sage: copy(x*y*z+z*y*x) == x*y*z+z*y*x # indirect doctest 116 True 117 118 """ 119 self._poly = (<FreeAlgebra_letterplace>self._parent)._current_ring(self._poly) 120 return self.__class__(self._parent,self._poly,check=False) 121 def __hash__(self): 122 """ 123 TEST:: 124 125 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 126 sage: set([x*y*z, z*y+x*z,x*y*z]) # indirect doctest 127 set([x*z + z*y, x*y*z]) 128 129 """ 130 return hash(self._poly) 131 def __iter__(self): 132 """ 133 Iterates over the pairs "tuple of exponents, coefficient". 134 135 EXAMPLE:: 136 137 sage: F.<w,x,y,z> = FreeAlgebra(GF(3), implementation='letterplace') 138 sage: p = x*y-z^2 139 sage: list(p) # indirect doctest 140 [((0, 0, 0, 1, 0, 0, 0, 1), 2), ((0, 1, 0, 0, 0, 0, 1, 0), 1)] 141 142 """ 143 return self._poly.dict().iteritems() 144 def _repr_(self): 145 """ 146 TEST:: 147 148 sage: K.<z> = GF(25) 149 sage: F.<a,b,c> = FreeAlgebra(K, implementation='letterplace') 150 sage: -(a+b*(z+1)-c)^2 # indirect doctest 151 -a*a + (4*z + 4)*a*b + a*c + (4*z + 4)*b*a + (2*z + 1)*b*b + (z + 1)*b*c + c*a + (z + 1)*c*b - c*c 152 153 It is possible to change the names temporarily:: 154 155 sage: from sage.structure.parent_gens import localvars 156 sage: with localvars(F, ['w', 'x','y']): 157 ... print a+b*(z+1)-c 158 w + (z + 1)*x - y 159 sage: print a+b*(z+1)-c 160 a + (z + 1)*b - c 161 162 """ 163 cdef list L = [] 164 cdef FreeAlgebra_letterplace P = self._parent 165 cdef int ngens = P.__ngens 166 if P._base.is_atomic_repr(): 167 for E,c in zip(self._poly.exponents(),self._poly.coefficients()): 168 monstr = P.exponents_to_string(E) 169 if monstr: 170 if c==1: 171 if L: 172 L.extend(['+',monstr]) 173 else: 174 L.append(monstr) 175 elif c==-1: 176 if L: 177 L.extend(['-',monstr]) 178 else: 179 L.append('-'+monstr) 180 else: 181 if L: 182 if c>=0: 183 L.extend(['+',repr(c)+'*'+monstr]) 184 else: 185 L.extend(['-',repr(-c)+'*'+monstr]) 186 else: 187 L.append(repr(c)+'*'+monstr) 188 else: 189 if c>=0: 190 if L: 191 L.extend(['+',repr(c)]) 192 else: 193 L.append(repr(c)) 194 else: 195 if L: 196 L.extend(['-',repr(-c)]) 197 else: 198 L.append(repr(c)) 199 else: 200 for E,c in zip(self._poly.exponents(),self._poly.coefficients()): 201 monstr = P.exponents_to_string(E) 202 if monstr: 203 if c==1: 204 if L: 205 L.extend(['+',monstr]) 206 else: 207 L.append(monstr) 208 elif c==-1: 209 if L: 210 L.extend(['-',monstr]) 211 else: 212 L.append('-'+monstr) 213 else: 214 if L: 215 L.extend(['+','('+repr(c)+')*'+monstr]) 216 else: 217 L.append('('+repr(c)+')*'+monstr) 218 else: 219 if L: 220 L.extend(['+',repr(c)]) 221 else: 222 L.append(repr(c)) 223 if L: 224 return ' '.join(L) 225 return '0' 226 227 def _latex_(self): 228 """ 229 TEST:: 230 231 sage: K.<z> = GF(25) 232 sage: F.<a,b,c> = FreeAlgebra(K, implementation='letterplace', degrees=[1,2,3]) 233 sage: -(a*b*(z+1)-c)^2 234 (2*z + 1)*a*b*a*b + (z + 1)*a*b*c + (z + 1)*c*a*b - c*c 235 sage: latex(-(a*b*(z+1)-c)^2) # indirect doctest 236 \left(2 z + 1\right) a b a b + \left(z + 1\right) a b c + \left(z + 1\right) c a b - c c 237 238 """ 239 cdef list L = [] 240 cdef FreeAlgebra_letterplace P = self._parent 241 cdef int ngens = P.__ngens 242 from sage.all import latex 243 if P._base.is_atomic_repr(): 244 for E,c in zip(self._poly.exponents(),self._poly.coefficients()): 245 monstr = P.exponents_to_latex(E) 246 if monstr: 247 if c==1: 248 if L: 249 L.extend(['+',monstr]) 250 else: 251 L.append(monstr) 252 elif c==-1: 253 if L: 254 L.extend(['-',monstr]) 255 else: 256 L.append('-'+monstr) 257 else: 258 if L: 259 if c>=0: 260 L.extend(['+',repr(latex(c))+' '+monstr]) 261 else: 262 L.extend(['-',repr(latex(-c))+' '+monstr]) 263 else: 264 L.append(repr(latex(c))+' '+monstr) 265 else: 266 if c>=0: 267 if L: 268 L.extend(['+',repr(latex(c))]) 269 else: 270 L.append(repr(latex(c))) 271 else: 272 if L: 273 L.extend(['-',repr(latex(-c))]) 274 else: 275 L.append(repr(c)) 276 else: 277 for E,c in zip(self._poly.exponents(),self._poly.coefficients()): 278 monstr = P.exponents_to_latex(E) 279 if monstr: 280 if c==1: 281 if L: 282 L.extend(['+',monstr]) 283 else: 284 L.append(monstr) 285 elif c==-1: 286 if L: 287 L.extend(['-',monstr]) 288 else: 289 L.append('-'+monstr) 290 else: 291 if L: 292 L.extend(['+','\\left('+repr(latex(c))+'\\right) '+monstr]) 293 else: 294 L.append('\\left('+repr(latex(c))+'\\right) '+monstr) 295 else: 296 if L: 297 L.extend(['+',repr(latex(c))]) 298 else: 299 L.append(repr(latex(c))) 300 if L: 301 return ' '.join(L) 302 return '0' 303 304 def degree(self): 305 """ 306 Return the degree of this element. 307 308 NOTE: 309 310 Generators may have a positive integral degree weight. All 311 elements must be weighted homogeneous. 312 313 EXAMPLE:: 314 315 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 316 sage: ((x+y+z)^3).degree() 317 3 318 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) 319 sage: ((x*y+z)^3).degree() 320 9 321 322 """ 323 return self._poly.degree() 324 325 def letterplace_polynomial(self): 326 """ 327 Return the commutative polynomial that is used internally to represent this free algebra element. 328 329 EXAMPLE:: 330 331 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 332 sage: ((x+y-z)^2).letterplace_polynomial() 333 x*x_1 + x*y_1 - x*z_1 + y*x_1 + y*y_1 - y*z_1 - z*x_1 - z*y_1 + z*z_1 334 335 If degree weights are used, the letterplace polynomial is 336 homogenized by slack variables:: 337 338 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) 339 sage: ((x*y+z)^2).letterplace_polynomial() 340 x*x__1*y_2*x_3*x__4*y_5 + x*x__1*y_2*z_3*x__4*x__5 + z*x__1*x__2*x_3*x__4*y_5 + z*x__1*x__2*z_3*x__4*x__5 341 342 """ 343 return self._poly 344 345 def lm(self): 346 """ 347 The leading monomial of this free algebra element. 348 349 EXAMPLE:: 350 351 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 352 sage: ((2*x+3*y-4*z)^2*(5*y+6*z)).lm() 353 x*x*y 354 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) 355 sage: ((2*x*y+z)^2).lm() 356 x*y*x*y 357 358 """ 359 return FreeAlgebraElement_letterplace(self._parent, self._poly.lm()) 360 361 def lt(self): 362 """ 363 The leading term (monomial times coefficient) of this free algebra 364 element. 365 366 EXAMPLE:: 367 368 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 369 sage: ((2*x+3*y-4*z)^2*(5*y+6*z)).lt() 370 20*x*x*y 371 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) 372 sage: ((2*x*y+z)^2).lt() 373 4*x*y*x*y 374 375 """ 376 return FreeAlgebraElement_letterplace(self._parent, self._poly.lt()) 377 378 def lc(self): 379 """ 380 The leading coefficient of this free algebra element, as element 381 of the base ring. 382 383 EXAMPLE:: 384 385 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 386 sage: ((2*x+3*y-4*z)^2*(5*y+6*z)).lc() 387 20 388 sage: ((2*x+3*y-4*z)^2*(5*y+6*z)).lc().parent() is F.base() 389 True 390 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) 391 sage: ((2*x*y+z)^2).lc() 392 4 393 394 """ 395 return self._poly.lc() 396 397 def __nonzero__(self): 398 """ 399 TEST:: 400 401 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 402 sage: bool(x) # indirect doctest 403 True 404 sage: bool(F.zero()) 405 False 406 407 """ 408 return bool(self._poly) 409 410 def lm_divides(self, FreeAlgebraElement_letterplace p): 411 """ 412 Tell whether or not the leading monomial of self devides the 413 leading monomial of another element. 414 415 NOTE: 416 417 A free algebra element `p` divides another one `q` if there are 418 free algebra elements `s` and `t` such that `spt = q`. 419 420 EXAMPLE:: 421 422 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) 423 sage: ((2*x*y+z)^2*z).lm() 424 x*y*x*y*z 425 sage: (y*x*y-y^4).lm() 426 y*x*y 427 sage: (y*x*y-y^4).lm_divides((2*x*y+z)^2*z) 428 True 429 430 """ 431 if self._parent is not p._parent: 432 raise TypeError, "The two arguments must be elements in the same free algebra." 433 cdef FreeAlgebra_letterplace A = self._parent 434 P = A._current_ring 435 p_poly = p._poly = P(p._poly) 436 s_poly = self._poly = P(self._poly) 437 cdef int p_d = p_poly.degree() 438 cdef int s_d = s_poly.degree() 439 if s_d>p_d: 440 return False 441 cdef int i 442 if P.monomial_divides(s_poly,p_poly): 443 return True 444 for i from 0 <= i < p_d-s_d: 445 s_poly = singular_system("stest",s_poly,1, 446 A._degbound,A.__ngens,ring=P) 447 if P.monomial_divides(s_poly,p_poly): 448 return True 449 return False 450 451 def __richcmp__(left, right, int op): 452 """ 453 TEST:: 454 455 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 456 sage: p = ((2*x+3*y-4*z)^2*(5*y+6*z)) 457 sage: p-p.lt()<p # indirect doctest 458 True 459 460 """ 461 return (<Element>left)._richcmp(right, op) 462 def __cmp__(left, right): 463 """ 464 TEST:: 465 466 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 467 sage: p = ((2*x+3*y-4*z)^2*(5*y+6*z)) 468 sage: cmp(p,p-p.lt()) # indirect doctest 469 1 470 471 """ 472 return (<Element>left)._cmp(right) 473 474 cdef int _cmp_c_impl(self, Element other) except -2: 475 """ 476 Auxiliary method for comparison. 477 478 TEST:: 479 480 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 481 sage: p = ((2*x+3*y-4*z)^2*(5*y+6*z)) 482 sage: p-p.lt()<p # indirect doctest 483 True 484 485 """ 486 cdef int c = cmp(type(self),type(other)) 487 if c: return c 488 return cmp((<FreeAlgebraElement_letterplace>self)._poly,(<FreeAlgebraElement_letterplace>other)._poly) 489 490 ################################ 491 ## Arithmetic 492 cpdef ModuleElement _neg_(self): 493 """ 494 TEST:: 495 496 sage: K.<z> = GF(25) 497 sage: F.<a,b,c> = FreeAlgebra(K, implementation='letterplace') 498 sage: -((z+2)*a^2*b+3*c^3) # indirect doctest 499 (4*z + 3)*a*a*b + (2)*c*c*c 500 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 501 sage: -(3*x*y+2*z^2) 502 -3*x*y - 2*z*z 503 504 """ 505 return FreeAlgebraElement_letterplace(self._parent,-self._poly,check=False) 506 cpdef ModuleElement _add_(self, ModuleElement other): 507 """ 508 Addition, under the side condition that either one summand 509 is zero, or both summands have the same degree. 510 511 TEST:: 512 513 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 514 sage: x+y # indirect doctest 515 x + y 516 sage: x+1 517 Traceback (most recent call last): 518 ... 519 ArithmeticError: Can only add elements of the same weighted degree 520 sage: x+0 521 x 522 sage: 0+x 523 x 524 525 """ 526 if not other: 527 return self 528 if not self: 529 return other 530 cdef FreeAlgebraElement_letterplace right = other 531 if right._poly.degree()!=self._poly.degree(): 532 raise ArithmeticError, "Can only add elements of the same weighted degree" 533 # update the polynomials 534 cdef FreeAlgebra_letterplace A = self._parent 535 self._poly = A._current_ring(self._poly) 536 right._poly = A._current_ring(right._poly) 537 return FreeAlgebraElement_letterplace(self._parent,self._poly+right._poly,check=False) 538 539 cpdef ModuleElement _sub_(self, ModuleElement other): 540 """ 541 Difference, under the side condition that either one summand 542 is zero or both have the same weighted degree. 543 544 TEST:: 545 546 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 547 sage: x*y-y*x # indirect doctest 548 x*y - y*x 549 sage: x-1 550 Traceback (most recent call last): 551 ... 552 ArithmeticError: Can only subtract elements of the same degree 553 sage: x-0 554 x 555 sage: 0-x 556 -x 557 558 Here is an example with non-trivial degree weights:: 559 560 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) 561 sage: x*y+z 562 x*y + z 563 564 """ 565 if not other: 566 return self 567 if not self: 568 return -other 569 cdef FreeAlgebraElement_letterplace right = other 570 if right._poly.degree()!=self._poly.degree(): 571 raise ArithmeticError, "Can only subtract elements of the same degree" 572 # update the polynomials 573 cdef FreeAlgebra_letterplace A = self._parent 574 self._poly = A._current_ring(self._poly) 575 right._poly = A._current_ring(right._poly) 576 return FreeAlgebraElement_letterplace(self._parent,self._poly-right._poly,check=False) 577 578 cpdef ModuleElement _lmul_(self, RingElement right): 579 """ 580 Multiplication from the right with an element of the base ring. 581 582 TEST:: 583 584 sage: K.<z> = GF(25) 585 sage: F.<a,b,c> = FreeAlgebra(K, implementation='letterplace') 586 sage: (a+b)*(z+1) # indirect doctest 587 (z + 1)*a + (z + 1)*b 588 589 """ 590 return FreeAlgebraElement_letterplace(self._parent,self._poly._lmul_(right),check=False) 591 592 cpdef ModuleElement _rmul_(self, RingElement left): 593 """ 594 Multiplication from the left with an element of the base ring. 595 596 TEST:: 597 598 sage: K.<z> = GF(25) 599 sage: F.<a,b,c> = FreeAlgebra(K, implementation='letterplace') 600 sage: (z+1)*(a+b) # indirect doctest 601 (z + 1)*a + (z + 1)*b 602 603 """ 604 return FreeAlgebraElement_letterplace(self._parent,self._poly._rmul_(left),check=False) 605 606 cpdef RingElement _mul_(self, RingElement other): 607 """ 608 Product of two free algebra elements in letterplace implementation. 609 610 TEST:: 611 612 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) 613 sage: (x*y+z)*z # indirect doctest 614 x*y*z + z*z 615 616 """ 617 cdef FreeAlgebraElement_letterplace left = self 618 cdef FreeAlgebraElement_letterplace right = other 619 cdef FreeAlgebra_letterplace A = left._parent 620 A.set_degbound(left._poly.degree()+right._poly.degree()) 621 # we must put the polynomials into the same ring 622 left._poly = A._current_ring(left._poly) 623 right._poly = A._current_ring(right._poly) 624 rshift = singular_system("stest",right._poly,left._poly.degree(),A._degbound,A.__ngens, ring=A._current_ring) 625 return FreeAlgebraElement_letterplace(A,left._poly*rshift, check=False) 626 627 def __pow__(FreeAlgebraElement_letterplace self, int n, k): 628 """ 629 TEST:: 630 631 sage: K.<z> = GF(25) 632 sage: F.<a,b,c> = FreeAlgebra(K, implementation='letterplace') 633 sage: (a+z*b)^3 # indirect doctest 634 a*a*a + (z)*a*a*b + (z)*a*b*a + (z + 3)*a*b*b + (z)*b*a*a + (z + 3)*b*a*b + (z + 3)*b*b*a + (4*z + 3)*b*b*b 635 636 """ 637 cdef FreeAlgebra_letterplace A = self._parent 638 if n<0: 639 raise ValueError, "Negative exponents are not allowed" 640 if n==0: 641 return FreeAlgebraElement_letterplace(A, A._current_ring(1), 642 check=False) 643 if n==1: 644 return self 645 A.set_degbound(self._poly.degree()*n) 646 cdef MPolynomial_libsingular p,q 647 self._poly = A._current_ring(self._poly) 648 cdef int d = self._poly.degree() 649 q = p = self._poly 650 cdef int i 651 for i from 0<i<n: 652 q = singular_system("stest",q,d,A._degbound,A.__ngens, 653 ring=A._current_ring) 654 p *= q 655 return FreeAlgebraElement_letterplace(A, p, check=False) 656 657 ## Groebner related stuff 658 def reduce(self, G): 659 """ 660 Reduce this element by a list of elements or by a 661 twosided weighted homogeneous ideal. 662 663 INPUT: 664 665 Either a list or tuple of weighted homogeneous elements of the 666 free algebra, or an ideal of the free algebra, or an ideal in 667 the commutative polynomial ring that is currently used to 668 implement the multiplication in the free algebra. 669 670 OUTPUT: 671 672 The twosided reduction of this element by the argument. 673 674 NOTE: 675 676 This may not be the normal form of this element, unless 677 the argument is a twosided Groebner basis up to the degree 678 of this element. 679 680 EXAMPLE:: 681 682 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 683 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 684 sage: p = y^2*z*y^2+y*z*y*z*y 685 686 We compute the letterplace version of the Groebneer basis 687 of `I` with degree bound 4:: 688 689 sage: G = F._reductor_(I.groebner_basis(4).gens(),4) 690 sage: G.ring() is F.current_ring() 691 True 692 693 Since the element `p` is of degree 5, it is no surrprise 694 that its reductions with respect to the original generators 695 of `I` (of degree 2), or with respect to `G` (Groebner basis 696 with degree bound 4), or with respect to the Groebner basis 697 with degree bound 5 (which yields its normal form) are 698 pairwise different:: 699 700 sage: p.reduce(I) 701 y*y*z*y*y + y*z*y*z*y 702 sage: p.reduce(G) 703 y*y*z*z*y + y*z*y*z*y - y*z*z*y*y + y*z*z*z*y 704 sage: p.normal_form(I) 705 y*y*z*z*z + y*z*y*z*z - y*z*z*y*z + y*z*z*z*z 706 sage: p.reduce(I) != p.reduce(G) != p.normal_form(I) != p.reduce(I) 707 True 708 709 """ 710 cdef FreeAlgebra_letterplace P = self._parent 711 if not isinstance(G,(list,tuple)): 712 if G==P: 713 return P.zero_element() 714 if not (isinstance(G,MPolynomialIdeal) and G.ring()==P._current_ring): 715 G = G.gens() 716 C = P.current_ring() 717 cdef int selfdeg = self._poly.degree() 718 if isinstance(G,MPolynomialIdeal): 719 gI = G 720 else: 721 gI = P._reductor_(G,selfdeg) #C.ideal(g,coerce=False) 722 from sage.libs.singular.option import LibSingularOptions 723 libsingular_options = LibSingularOptions() 724 bck = (libsingular_options['redTail'],libsingular_options['redSB']) 725 libsingular_options['redTail'] = True 726 libsingular_options['redSB'] = True 727 poly = poly_reduce(C(self._poly),gI, ring=C, 728 attributes={gI:{"isSB":1}}) 729 libsingular_options['redTail'] = bck[0] 730 libsingular_options['redSB'] = bck[1] 731 return FreeAlgebraElement_letterplace(P,poly,check=False) 732 733 def normal_form(self,I): 734 """ 735 Return the normal form of this element with respect to 736 a twosided weighted homogeneous ideal. 737 738 INPUT: 739 740 A twosided homogeneous ideal `I` of the parent `F` of 741 this element, `x`. 742 743 OUTPUT: 744 745 The normal form of `x` wrt. `I`. 746 747 NOTE: 748 749 The normal form is computed by reduction with respect 750 to a Groebnerbasis of `I` with degree bound `deg(x)`. 751 752 EXAMPLE:: 753 754 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 755 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 756 sage: (x^5).normal_form(I) 757 -y*z*z*z*x - y*z*z*z*y - y*z*z*z*z 758 759 We verify two basic properties of normal forms: The 760 difference of an element and its normal form is contained 761 in the ideal, and if two elements of the free algebra 762 differ by an element of the ideal then they have the same 763 normal form:: 764 765 sage: x^5 - (x^5).normal_form(I) in I 766 True 767 sage: (x^5+x*I.0*y*z-3*z^2*I.1*y).normal_form(I) == (x^5).normal_form(I) 768 True 769 770 Here is an example with non-trivial degree weights:: 771 772 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[1,2,3]) 773 sage: I = F*[x*y-y*x+z, y^2+2*x*z, (x*y)^2-z^2]*F 774 sage: ((x*y)^3).normal_form(I) 775 z*z*y*x - z*z*z 776 sage: (x*y)^3-((x*y)^3).normal_form(I) in I 777 True 778 sage: ((x*y)^3+2*z*I.0*z+y*I.1*z-x*I.2*y).normal_form(I) == ((x*y)^3).normal_form(I) 779 True 780 781 """ 782 if self._parent != I.ring(): 783 raise ValueError, "Can not compute normal form wrt an ideal that does not belong to %s"%self._parent 784 sdeg = self._poly.degree() 785 return self.reduce(self._parent._reductor_(I.groebner_basis(degbound=sdeg).gens(), sdeg)) -
new file sage/algebras/letterplace/free_algebra_letterplace.pxd
diff --git a/sage/algebras/letterplace/free_algebra_letterplace.pxd b/sage/algebras/letterplace/free_algebra_letterplace.pxd new file mode 100644
- + 1 ############################################################################### 2 # 3 # Copyright (C) 2011 Simon King <simon.king@uni-jena.de> 4 # Distributed under the terms of the GNU General Public License (GPL), 5 # version 2 or any later version. The full text of the GPL is available at: 6 # http://www.gnu.org/licenses/ 7 # 8 ############################################################################### 9 10 cdef class FreeAlgebra_letterplace 11 12 from sage.rings.ring cimport Algebra 13 from sage.structure.element cimport AlgebraElement, ModuleElement, RingElement, Element 14 from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular, MPolynomial_libsingular 15 from sage.algebras.letterplace.free_algebra_element_letterplace cimport FreeAlgebraElement_letterplace 16 17 include "../../ext/stdsage.pxi" 18 19 cdef class FreeAlgebra_letterplace(Algebra): 20 cdef MPolynomialRing_libsingular _commutative_ring 21 cdef MPolynomialRing_libsingular _current_ring 22 cdef int _degbound 23 cdef int __ngens 24 cdef int _nb_slackvars 25 cdef object __monoid 26 cdef public object __custom_name 27 cdef str exponents_to_string(self, E) 28 cdef str exponents_to_latex(self, E) 29 cdef tuple _degrees -
new file sage/algebras/letterplace/free_algebra_letterplace.pyx
diff --git a/sage/algebras/letterplace/free_algebra_letterplace.pyx b/sage/algebras/letterplace/free_algebra_letterplace.pyx new file mode 100644
- + 1 ############################################################################### 2 # 3 # Copyright (C) 2011 Simon King <simon.king@uni-jena.de> 4 # Distributed under the terms of the GNU General Public License (GPL), 5 # version 2 or any later version. The full text of the GPL is available at: 6 # http://www.gnu.org/licenses/ 7 # 8 ############################################################################### 9 10 """ 11 Free associative unital algebras, implemented via Singular's letterplace rings 12 13 AUTHOR: 14 15 - Simon King (2011-03-21): :trac:`7797` 16 17 With this implementation, Groebner bases out to a degree bound and 18 normal forms can be computed for twosided weighted homogeneous ideals 19 of free algebras. For now, all computations are restricted to weighted 20 homogeneous elements, i.e., other elements can not be created by 21 arithmetic operations. 22 23 EXAMPLES:: 24 25 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 26 sage: F 27 Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 28 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 29 sage: I 30 Twosided Ideal (x*y + y*z, x*x + x*y - y*x - y*y) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 31 sage: x*(x*I.0-I.1*y+I.0*y)-I.1*y*z 32 x*y*x*y + x*y*y*y - x*y*y*z + x*y*z*y + y*x*y*z + y*y*y*z 33 sage: x^2*I.0-x*I.1*y+x*I.0*y-I.1*y*z in I 34 True 35 36 The preceding containment test is based on the computation of Groebner 37 bases with degree bound:: 38 39 sage: I.groebner_basis(degbound=4) 40 Twosided Ideal (y*z*y*y - y*z*y*z + y*z*z*y - y*z*z*z, y*z*y*x + y*z*y*z + y*z*z*x + y*z*z*z, y*y*z*y - y*y*z*z + y*z*z*y - y*z*z*z, y*y*z*x + y*y*z*z + y*z*z*x + y*z*z*z, y*y*y - y*y*z + y*z*y - y*z*z, y*y*x + y*y*z + y*z*x + y*z*z, x*y + y*z, x*x - y*x - y*y - y*z) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 41 42 When reducing an element by `I`, the original generators are chosen:: 43 44 sage: (y*z*y*y).reduce(I) 45 y*z*y*y 46 47 However, there is a method for computing the normal form of an 48 element, which is the same as reduction by the Groebner basis out to 49 the degree of that element:: 50 51 sage: (y*z*y*y).normal_form(I) 52 y*z*y*z - y*z*z*y + y*z*z*z 53 sage: (y*z*y*y).reduce(I.groebner_basis(4)) 54 y*z*y*z - y*z*z*y + y*z*z*z 55 56 The default term order derives from the degree reverse lexicographic 57 order on the commutative version of the free algebra:: 58 59 sage: F.commutative_ring().term_order() 60 Degree reverse lexicographic term order 61 62 A different term order can be chosen, and of course may yield a 63 different normal form:: 64 65 sage: L.<a,b,c> = FreeAlgebra(QQ, implementation='letterplace', order='lex') 66 sage: L.commutative_ring().term_order() 67 Lexicographic term order 68 sage: J = L*[a*b+b*c,a^2+a*b-b*c-c^2]*L 69 sage: J.groebner_basis(4) 70 Twosided Ideal (2*b*c*b - b*c*c + c*c*b, a*c*c - 2*b*c*a - 2*b*c*c - c*c*a, a*b + b*c, a*a - 2*b*c - c*c) of Free Associative Unital Algebra on 3 generators (a, b, c) over Rational Field 71 sage: (b*c*b*b).normal_form(J) 72 1/2*b*c*c*b - 1/2*c*c*b*b 73 74 Here is an example with degree weights:: 75 76 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[1,2,3]) 77 sage: (x*y+z).degree() 78 3 79 80 TEST:: 81 82 sage: TestSuite(F).run() 83 sage: TestSuite(L).run() 84 sage: loads(dumps(F)) is F 85 True 86 87 TODO: 88 89 The computation of Groebner bases only works for global term 90 orderings, and all elements must be weighted homogeneous with respect 91 to positive integral degree weights. It is ongoing work in Singular to 92 lift these restrictions. 93 94 We support coercion from the letterplace wrapper to the corresponding 95 generic implementation of a free algebra 96 (:class:`~sage.algebras.free_algebra.FreeAlgebra_generic`), but there 97 is no coercion in the opposite direction, since the generic 98 implementation also comprises non-homogeneous elements. 99 100 We also do not support coercion from a subalgebra, or between free 101 algebras with different term orderings, yet. 102 103 """ 104 105 from sage.all import PolynomialRing, prod 106 from sage.libs.singular.function import lib, singular_function 107 from sage.rings.polynomial.term_order import TermOrder 108 from sage.rings.polynomial.multi_polynomial_ring_generic import MPolynomialRing_generic 109 from sage.categories.algebras import Algebras 110 from sage.rings.noncommutative_ideals import IdealMonoid_nc 111 112 ##################### 113 # Define some singular functions 114 lib("freegb.lib") 115 poly_reduce = singular_function("NF") 116 singular_system=singular_function("system") 117 118 # unfortunately we can not set Singular attributes for MPolynomialRing_libsingular 119 # Hence, we must constantly work around Letterplace's sanity checks, 120 # and can not use the following library functions: 121 #set_letterplace_attributes = singular_function("setLetterplaceAttributes") 122 #lpMult = singular_function("lpMult") 123 124 ##################### 125 # Auxiliar functions 126 127 cdef MPolynomialRing_libsingular make_letterplace_ring(base_ring,blocks): 128 """ 129 Create a polynomial ring in block order. 130 131 INPUT: 132 133 - ``base_ring``: A multivariate polynomial ring. 134 - ``blocks``: The number of blocks to be formed. 135 136 OUTPUT: 137 138 A multivariate polynomial ring in block order, all blocks 139 isomorphic (as ordered rings) with the given ring, and the 140 variable names of the `n`-th block (`n>0`) ending with 141 ``"_%d"%n``. 142 143 TEST: 144 145 Note that, since the algebras are cached, we need to choose 146 a different base ring, since other doctests could have a 147 side effect on the atteined degree bound:: 148 149 sage: F.<x,y,z> = FreeAlgebra(GF(17), implementation='letterplace') 150 sage: L.<a,b,c> = FreeAlgebra(GF(17), implementation='letterplace', order='lex') 151 sage: F.set_degbound(4) 152 sage: F.current_ring() # indirect doctest 153 Multivariate Polynomial Ring in x, y, z, x_1, y_1, z_1, x_2, y_2, z_2, x_3, y_3, z_3 over Finite Field of size 17 154 sage: F.current_ring().term_order() 155 Block term order with blocks: 156 (Degree reverse lexicographic term order of length 3, 157 Degree reverse lexicographic term order of length 3, 158 Degree reverse lexicographic term order of length 3, 159 Degree reverse lexicographic term order of length 3) 160 sage: L.set_degbound(2) 161 sage: L.current_ring().term_order() 162 Block term order with blocks: 163 (Lexicographic term order of length 3, 164 Lexicographic term order of length 3) 165 166 """ 167 n = base_ring.ngens() 168 T0 = base_ring.term_order() 169 T = T0 170 cdef i 171 cdef tuple names0 = base_ring.variable_names() 172 cdef list names = list(names0) 173 for i from 1<=i<blocks: 174 T += T0 175 names.extend([x+'_'+str(i) for x in names0]) 176 return PolynomialRing(base_ring.base_ring(),len(names),names,order=T) 177 178 ##################### 179 # The free algebra 180 181 cdef class FreeAlgebra_letterplace(Algebra): 182 """ 183 Finitely generated free algebra, with arithmetic restricted to weighted homogeneous elements. 184 185 NOTE: 186 187 The restriction to weighted homogeneous elements should be lifted 188 as soon as the restriction to homogeneous elements is lifted in 189 Singular's "Letterplace algebras". 190 191 EXAMPLE:: 192 193 sage: K.<z> = GF(25) 194 sage: F.<a,b,c> = FreeAlgebra(K, implementation='letterplace') 195 sage: F 196 Free Associative Unital Algebra on 3 generators (a, b, c) over Finite Field in z of size 5^2 197 sage: P = F.commutative_ring() 198 sage: P 199 Multivariate Polynomial Ring in a, b, c over Finite Field in z of size 5^2 200 201 We can do arithmetic as usual, as long as we stay (weighted) homogeneous:: 202 203 sage: (z*a+(z+1)*b+2*c)^2 204 (z + 3)*a*a + (2*z + 3)*a*b + (2*z)*a*c + (2*z + 3)*b*a + (3*z + 4)*b*b + (2*z + 2)*b*c + (2*z)*c*a + (2*z + 2)*c*b - c*c 205 sage: a+1 206 Traceback (most recent call last): 207 ... 208 ArithmeticError: Can only add elements of the same weighted degree 209 210 """ 211 # It is not really a free algebra over the given generators. Rather, 212 # it is a free algebra over the commutative monoid generated by the given generators. 213 def __init__(self, R, degrees=None): 214 """ 215 INPUT: 216 217 A multivariate polynomial ring of type :class:`~sage.rings.polynomial.multipolynomial_libsingular.MPolynomialRing_libsingular`. 218 219 OUTPUT: 220 221 The free associative version of the given commutative ring. 222 223 NOTE: 224 225 One is supposed to use the `FreeAlgebra` constructor, in order to use the cache. 226 227 TEST:: 228 229 sage: from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace 230 sage: FreeAlgebra_letterplace(QQ['x','y']) 231 Free Associative Unital Algebra on 2 generators (x, y) over Rational Field 232 sage: FreeAlgebra_letterplace(QQ['x']) 233 Traceback (most recent call last): 234 ... 235 TypeError: A letterplace algebra must be provided by a polynomial ring of type <type 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomialRing_libsingular'> 236 237 :: 238 239 sage: K.<z> = GF(25) 240 sage: F.<a,b,c> = FreeAlgebra(K, implementation='letterplace') 241 sage: TestSuite(F).run(verbose=True) 242 running ._test_additive_associativity() . . . pass 243 running ._test_an_element() . . . pass 244 running ._test_associativity() . . . pass 245 running ._test_category() . . . pass 246 running ._test_characteristic() . . . pass 247 running ._test_distributivity() . . . pass 248 running ._test_elements() . . . 249 Running the test suite of self.an_element() 250 running ._test_category() . . . pass 251 running ._test_eq() . . . pass 252 running ._test_not_implemented_methods() . . . pass 253 running ._test_pickling() . . . pass 254 pass 255 running ._test_elements_eq() . . . pass 256 running ._test_eq() . . . pass 257 running ._test_not_implemented_methods() . . . pass 258 running ._test_one() . . . pass 259 running ._test_pickling() . . . pass 260 running ._test_prod() . . . pass 261 running ._test_some_elements() . . . pass 262 running ._test_zero() . . . pass 263 264 """ 265 if not isinstance(R,MPolynomialRing_libsingular): 266 raise TypeError, "A letterplace algebra must be provided by a polynomial ring of type %s"%MPolynomialRing_libsingular 267 self.__ngens = R.ngens() 268 if degrees is None: 269 varnames = R.variable_names() 270 self._nb_slackvars = 0 271 else: 272 varnames = R.variable_names()[:-1] 273 self._nb_slackvars = 1 274 base_ring = R.base_ring() 275 Algebra.__init__(self, base_ring, varnames, 276 normalize=False, category=Algebras(base_ring)) 277 self._commutative_ring = R 278 self._current_ring = make_letterplace_ring(R,1) 279 self._degbound = 1 280 if degrees is None: 281 self._degrees = tuple([int(1)]*self.__ngens) 282 else: 283 if (not isinstance(degrees,(tuple,list))) or len(degrees)!=self.__ngens-1 or any([i<=0 for i in degrees]): 284 raise TypeError, "The generator degrees must be given by a list or tuple of %d positive integers"%(self.__ngens-1) 285 self._degrees = tuple([int(i) for i in degrees]) 286 self.set_degbound(max(self._degrees)) 287 self._populate_coercion_lists_(coerce_list=[base_ring]) 288 def __reduce__(self): 289 """ 290 TEST:: 291 292 sage: K.<z> = GF(25) 293 sage: F.<a,b,c> = FreeAlgebra(K, implementation='letterplace') 294 sage: loads(dumps(F)) is F # indirect doctest 295 True 296 297 """ 298 from sage.algebras.free_algebra import FreeAlgebra 299 if self._nb_slackvars==0: 300 return FreeAlgebra,(self._commutative_ring,) 301 return FreeAlgebra,(self._commutative_ring,None,None,None,None,None,None,None,self._degrees) 302 # Small methods 303 def ngens(self): 304 """ 305 Return the number of generators. 306 307 EXAMPLE:: 308 309 sage: F.<a,b,c> = FreeAlgebra(QQ, implementation='letterplace') 310 sage: F.ngens() 311 3 312 313 """ 314 return self.__ngens-self._nb_slackvars 315 def gen(self,i): 316 """ 317 Return the `i`-th generator. 318 319 INPUT: 320 321 `i` -- an integer. 322 323 OUTPUT: 324 325 Generator number `i`. 326 327 EXAMPLE:: 328 329 sage: F.<a,b,c> = FreeAlgebra(QQ, implementation='letterplace') 330 sage: F.1 is F.1 # indirect doctest 331 True 332 sage: F.gen(2) 333 c 334 335 """ 336 if i>=self.__ngens-self._nb_slackvars: 337 raise ValueError, "This free algebra only has %d generators"%(self.__ngens-self._nb_slackvars) 338 if self._gens is not None: 339 return self._gens[i] 340 deg = self._degrees[i] 341 #self.set_degbound(deg) 342 p = self._current_ring.gen(i) 343 cdef int n 344 cdef int j = self.__ngens-1 345 for n from 1<=n<deg: 346 j += self.__ngens 347 p *= self._current_ring.gen(j) 348 return FreeAlgebraElement_letterplace(self, p) 349 def current_ring(self): 350 """ 351 Return the commutative ring that is used to emulate 352 the non-commutative multiplication out to the current degree. 353 354 EXAMPLE:: 355 356 sage: F.<a,b,c> = FreeAlgebra(QQ, implementation='letterplace') 357 sage: F.current_ring() 358 Multivariate Polynomial Ring in a, b, c over Rational Field 359 sage: a*b 360 a*b 361 sage: F.current_ring() 362 Multivariate Polynomial Ring in a, b, c, a_1, b_1, c_1 over Rational Field 363 sage: F.set_degbound(3) 364 sage: F.current_ring() 365 Multivariate Polynomial Ring in a, b, c, a_1, b_1, c_1, a_2, b_2, c_2 over Rational Field 366 367 """ 368 return self._current_ring 369 def commutative_ring(self): 370 """ 371 Return the commutative version of this free algebra. 372 373 NOTE: 374 375 This commutative ring is used as a unique key of the free algebra. 376 377 EXAMPLE:: 378 379 sage: K.<z> = GF(25) 380 sage: F.<a,b,c> = FreeAlgebra(K, implementation='letterplace') 381 sage: F 382 Free Associative Unital Algebra on 3 generators (a, b, c) over Finite Field in z of size 5^2 383 sage: F.commutative_ring() 384 Multivariate Polynomial Ring in a, b, c over Finite Field in z of size 5^2 385 sage: FreeAlgebra(F.commutative_ring()) is F 386 True 387 388 """ 389 return self._commutative_ring 390 def term_order_of_block(self): 391 """ 392 Return the term order that is used for the commutative version of this free algebra. 393 394 EXAMPLE:: 395 396 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 397 sage: F.term_order_of_block() 398 Degree reverse lexicographic term order 399 sage: L.<a,b,c> = FreeAlgebra(QQ, implementation='letterplace',order='lex') 400 sage: L.term_order_of_block() 401 Lexicographic term order 402 403 """ 404 return self._commutative_ring.term_order() 405 406 def generator_degrees(self): 407 return self._degrees 408 409 # Some basic properties of this ring 410 def is_commutative(self): 411 """ 412 Tell whether this algebra is commutative, i.e., whether the generator number is one. 413 414 EXAMPLE:: 415 416 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 417 sage: F.is_commutative() 418 False 419 sage: FreeAlgebra(QQ, implementation='letterplace', names=['x']).is_commutative() 420 True 421 422 """ 423 return self.__ngens-self._nb_slackvars <= 1 424 425 def is_field(self): 426 """ 427 Tell whether this free algebra is a field. 428 429 NOTE: 430 431 This would only be the case in the degenerate case of no generators. 432 But such an example can not be constructed in this implementation. 433 434 TEST:: 435 436 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 437 sage: F.is_field() 438 False 439 440 """ 441 return (not (self.__ngens-self._nb_slackvars)) and self._base.is_field() 442 443 def _repr_(self): 444 """ 445 EXAMPLE:: 446 447 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 448 sage: F # indirect doctest 449 Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 450 451 The degree weights are not part of the string representation:: 452 453 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) 454 sage: F 455 Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 456 457 458 """ 459 return "Free Associative Unital Algebra on %d generators %s over %s"%(self.__ngens-self._nb_slackvars,self.gens(),self._base) 460 461 def _latex_(self): 462 """ 463 Representation of this free algebra in LaTeX. 464 465 EXAMPLE:: 466 467 sage: F.<bla,alpha,z> = FreeAlgebra(QQ, implementation='letterplace', degrees=[1,2,3]) 468 sage: latex(F) 469 \Bold{Q}\langle \mbox{bla}, \alpha, z\rangle 470 471 """ 472 from sage.all import latex 473 return "%s\\langle %s\\rangle"%(latex(self.base_ring()),', '.join(self.latex_variable_names())) 474 475 def degbound(self): 476 """ 477 Return the degree bound that is currently used. 478 479 NOTE: 480 481 When multiplying two elements of this free algebra, the degree 482 bound will be dynamically adapted. It can also be set by 483 :meth:`set_degbound`. 484 485 EXAMPLE: 486 487 In order to avoid we get a free algebras from the cache that 488 was created in another doctest and has a different degree 489 bound, we choose a base ring that does not appear in other tests:: 490 491 sage: F.<x,y,z> = FreeAlgebra(ZZ, implementation='letterplace') 492 sage: F.degbound() 493 1 494 sage: x*y 495 x*y 496 sage: F.degbound() 497 2 498 sage: F.set_degbound(4) 499 sage: F.degbound() 500 4 501 502 """ 503 return self._degbound 504 def set_degbound(self,d): 505 """ 506 Increase the degree bound that is currently in place. 507 508 NOTE: 509 510 The degree bound can not be decreased. 511 512 EXAMPLE: 513 514 In order to avoid we get a free algebras from the cache that 515 was created in another doctest and has a different degree 516 bound, we choose a base ring that does not appear in other tests:: 517 518 sage: F.<x,y,z> = FreeAlgebra(GF(251), implementation='letterplace') 519 sage: F.degbound() 520 1 521 sage: x*y 522 x*y 523 sage: F.degbound() 524 2 525 sage: F.set_degbound(4) 526 sage: F.degbound() 527 4 528 sage: F.set_degbound(2) 529 sage: F.degbound() 530 4 531 532 """ 533 if d<=self._degbound: 534 return 535 self._degbound = d 536 self._current_ring = make_letterplace_ring(self._commutative_ring,d) 537 538 # def base_extend(self, R): 539 # if self._base.has_coerce_map_from(R): 540 # return self 541 542 ################################################ 543 ## Ideals 544 545 def _ideal_class_(self, n=0): 546 """ 547 Return the class :class:`~sage.algebras.letterplace.letterplace_ideal.LetterplaceIdeal`. 548 549 EXAMPLE:: 550 551 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 552 sage: I = [x*y+y*z,x^2+x*y-y*x-y^2]*F 553 sage: I 554 Right Ideal (x*y + y*z, x*x + x*y - y*x - y*y) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 555 sage: type(I) is F._ideal_class_() 556 True 557 558 """ 559 from sage.algebras.letterplace.letterplace_ideal import LetterplaceIdeal 560 return LetterplaceIdeal 561 562 def ideal_monoid(self): 563 """ 564 Return the monoid of ideals of this free algebra. 565 566 EXAMPLE:: 567 568 sage: F.<x,y> = FreeAlgebra(GF(2), implementation='letterplace') 569 sage: F.ideal_monoid() 570 Monoid of ideals of Free Associative Unital Algebra on 2 generators (x, y) over Finite Field of size 2 571 sage: F.ideal_monoid() is F.ideal_monoid() 572 True 573 574 """ 575 if self.__monoid is None: 576 self.__monoid = IdealMonoid_nc(self) 577 return self.__monoid 578 579 # Auxiliar methods 580 cdef str exponents_to_string(self, E): 581 """ 582 This auxiliary method is used for the string representation of elements of this free algebra. 583 584 EXAMPLE:: 585 586 sage: F.<x,y,z> = FreeAlgebra(GF(2), implementation='letterplace') 587 sage: x*y*x*z # indirect doctest 588 x*y*x*z 589 590 It should be possible to use the letterplace algebra to implement the 591 free algebra generated by the elements of a finitely generated free abelian 592 monoid. However, we can not use it, yet. So, for now, we raise an error:: 593 594 sage: from sage.algebras.letterplace.free_algebra_element_letterplace import FreeAlgebraElement_letterplace 595 sage: P = F.commutative_ring() 596 sage: FreeAlgebraElement_letterplace(F, P.0*P.1^2+P.1^3) # indirect doctest 597 Traceback (most recent call last): 598 ... 599 NotImplementedError: 600 Apparently you tried to view the letterplace algebra with 601 shift-multiplication as the free algebra over a finitely 602 generated free abelian monoid. 603 In principle, this is correct, but it is not implemented, yet. 604 605 """ 606 cdef int ngens = self.__ngens 607 cdef int nblocks = len(E)/ngens 608 cdef int i,j,base, exp, var_ind 609 cdef list out = [] 610 cdef list tmp 611 for i from 0<=i<nblocks: 612 base = i*ngens 613 tmp = [(j,E[base+j]) for j in xrange(ngens) if E[base+j]] 614 if not tmp: 615 continue 616 var_ind, exp = tmp[0] 617 if len(tmp)>1 or exp>1: 618 raise NotImplementedError, "\n Apparently you tried to view the letterplace algebra with\n shift-multiplication as the free algebra over a finitely\n generated free abelian monoid.\n In principle, this is correct, but it is not implemented, yet." 619 620 out.append(self._names[var_ind]) 621 i += (self._degrees[var_ind]-1) 622 ### This was the original implementation, with "monoid hack" but without generator degrees 623 #s = '.'.join([('%s^%d'%(x,e) if e>1 else x) for x,e in zip(self._names,E[i*ngens:(i+1)*ngens]) if e]) 624 #if s: 625 # out.append(s) 626 return '*'.join(out) 627 628 # Auxiliar methods 629 cdef str exponents_to_latex(self, E): 630 """ 631 This auxiliary method is used for the representation of elements of this free algebra as a latex string. 632 633 EXAMPLE:: 634 635 sage: K.<z> = GF(25) 636 sage: F.<a,b,c> = FreeAlgebra(K, implementation='letterplace', degrees=[1,2,3]) 637 sage: -(a*b*(z+1)-c)^2 638 (2*z + 1)*a*b*a*b + (z + 1)*a*b*c + (z + 1)*c*a*b - c*c 639 sage: latex(-(a*b*(z+1)-c)^2) # indirect doctest 640 \left(2 z + 1\right) a b a b + \left(z + 1\right) a b c + \left(z + 1\right) c a b - c c 641 642 """ 643 cdef int ngens = self.__ngens 644 cdef int nblocks = len(E)/ngens 645 cdef int i,j,base, exp, var_ind 646 cdef list out = [] 647 cdef list tmp 648 cdef list names = self.latex_variable_names() 649 for i from 0<=i<nblocks: 650 base = i*ngens 651 tmp = [(j,E[base+j]) for j in xrange(ngens) if E[base+j]] 652 if not tmp: 653 continue 654 var_ind, exp = tmp[0] 655 if len(tmp)>1 or exp>1: 656 raise NotImplementedError, "\n Apparently you tried to view the letterplace algebra with\n shift-multiplication as the free algebra over a finitely\n generated free abelian monoid.\n In principle, this is correct, but it is not implemented, yet." 657 658 out.append(names[var_ind]) 659 i += (self._degrees[var_ind]-1) 660 return ' '.join(out) 661 662 def _reductor_(self, g, d): 663 """ 664 Return a commutative ideal that can be used to compute the normal 665 form of a free algebra element of a given degree. 666 667 INPUT: 668 669 ``g`` - a list of elements of this free algebra. 670 ``d`` - an integer. 671 672 OUTPUT: 673 674 An ideal such that reduction of a letterplace polynomial by that ideal corresponds 675 to reduction of an element of degree at most ``d`` by ``g``. 676 677 EXAMPLE:: 678 679 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 680 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 681 sage: p = y*x*y + y*y*y + y*z*y - y*z*z 682 sage: p.reduce(I) 683 y*y*y - y*y*z + y*z*y - y*z*z 684 sage: G = F._reductor_(I.gens(),3); G 685 Ideal (x*y_1 + y*z_1, x_1*y_2 + y_1*z_2, x*x_1 + x*y_1 - y*x_1 - y*y_1, x_1*x_2 + x_1*y_2 - y_1*x_2 - y_1*y_2) of Multivariate Polynomial Ring in x, y, z, x_1, y_1, z_1, x_2, y_2, z_2... over Rational Field 686 687 We do not use the usual reduction method for polynomials in 688 Sage, since it does the reductions in a different order 689 compared to Singular. Therefore, we call the original Singular 690 reduction method, and prevent a warning message by asserting 691 that `G` is a Groebner basis. 692 693 sage: from sage.libs.singular.function import singular_function 694 sage: poly_reduce = singular_function("NF") 695 sage: q = poly_reduce(p.letterplace_polynomial(), G, ring=F.current_ring(), attributes={G:{"isSB":1}}); q 696 y*y_1*y_2 - y*y_1*z_2 + y*z_1*y_2 - y*z_1*z_2 697 sage: p.reduce(I).letterplace_polynomial() == q 698 True 699 700 """ 701 cdef list out = [] 702 C = self.current_ring() 703 cdef FreeAlgebraElement_letterplace x 704 ngens = self.__ngens 705 degbound = self._degbound 706 cdef list G = [C(x._poly) for x in g] 707 for y in G: 708 out.extend([y]+[singular_system("stest",y,n+1,degbound,ngens,ring=C) for n in xrange(d-y.degree())]) 709 return C.ideal(out) 710 711 ########################### 712 ## Coercion 713 cpdef _coerce_map_from_(self,S): 714 """ 715 A ring ``R`` coerces into self, if 716 717 - it coerces into the current polynomial ring, or 718 - it is a free graded algebra in letterplace implementation, 719 the generator names of ``R`` are a proper subset of the 720 generator names of self, the degrees of equally named 721 generators are equal, and the base ring of ``R`` coerces 722 into the base ring of self. 723 724 TEST: 725 726 Coercion from the base ring:: 727 728 sage: F.<x,y,z> = FreeAlgebra(GF(5), implementation='letterplace') 729 sage: 5 == F.zero() # indirect doctest 730 True 731 732 Coercion from another free graded algebra:: 733 734 sage: F.<t,y,z> = FreeAlgebra(ZZ, implementation='letterplace', degrees=[4,2,3]) 735 sage: G = FreeAlgebra(GF(5), implementation='letterplace', names=['x','y','z','t'], degrees=[1,2,3,4]) 736 sage: t*G.0 # indirect doctest 737 t*x 738 739 """ 740 if self==S or self._current_ring.has_coerce_map_from(S): 741 return True 742 cdef int i 743 # Do we have another letterplace algebra? 744 if not isinstance(S, FreeAlgebra_letterplace): 745 return False 746 # Do the base rings coerce? 747 if not self.base_ring().has_coerce_map_from(S.base_ring()): 748 return False 749 # Do the names match? 750 cdef tuple degs, Sdegs, names, Snames 751 names = self.variable_names() 752 Snames = S.variable_names() 753 if not set(names).issuperset(Snames): 754 return False 755 # Do the degrees match 756 degs = self._degrees 757 Sdegs = (<FreeAlgebra_letterplace>S)._degrees 758 for i from 0<=i<S.ngens(): 759 if degs[names.index(Snames[i])] != Sdegs[i]: 760 return False 761 return True 762 763 def _an_element_(self): 764 """ 765 Return an element. 766 767 EXAMPLE:: 768 769 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 770 sage: F.an_element() # indirect doctest 771 x 772 773 """ 774 return FreeAlgebraElement_letterplace(self, self._current_ring.an_element(), check=False) 775 776 # def random_element(self, degree=2, terms=5): 777 # """ 778 # Return a random element of a given degree and with a given number of terms. 779 # 780 # INPUT: 781 # 782 # - ``degree`` -- the maximal degree of the output (default 2). 783 # - ``terms`` -- the maximal number of terms of the output (default 5). 784 # 785 # NOTE: 786 # 787 # This method is currently not useful at all. 788 # 789 # Not tested. 790 # """ 791 # self.set_degbound(degree) 792 # while(1): 793 # p = self._current_ring.random_element(degree=degree,terms=terms) 794 # if p.is_homogeneous(): 795 # break 796 # return FreeAlgebraElement_letterplace(self, p, check=False) 797 798 def _from_dict_(self, D, check=True): 799 """ 800 Create an element from a dictionary. 801 802 INPUT: 803 804 - A dictionary. Keys: tuples of exponents. Values: 805 The coefficients of the corresponding monomial 806 in the to-be-created element. 807 - ``check`` (optional bool, default ``True``): 808 This is forwarded to the initialisation of 809 :class:`~sage.algebas.letterplace.free_algebra_element_letterplace.FreeAlgebraElement_letterplace`. 810 811 TEST: 812 813 This method applied to the dictionary of any element must 814 return the same element. This must hold true even if the 815 underlying letterplace ring has been extended in the meantime. 816 :: 817 818 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 819 sage: p = 3*x*y+2*z^2 820 sage: F.set_degbound(10) 821 sage: p == F._from_dict_(dict(p)) 822 True 823 824 For the empty dictionary, zero is returned:: 825 826 sage: F._from_dict_({}) 827 0 828 829 """ 830 if not D: 831 return self.zero_element() 832 cdef int l 833 for e in D.iterkeys(): 834 l = len(e) 835 break 836 cdef dict out = {} 837 self.set_degbound(l/self.__ngens) 838 cdef int n = self._current_ring.ngens() 839 for e,c in D.iteritems(): 840 out[tuple(e)+(0,)*(n-l)] = c 841 return FreeAlgebraElement_letterplace(self,self._current_ring(out), 842 check=check) 843 844 def _element_constructor_(self, x): 845 """ 846 Return an element of this free algebra. 847 848 INPUT: 849 850 An element of a free algebra with a proper subset of generator 851 names, or anything that can be interpreted in the polynomial 852 ring that is used to implement the letterplace algebra out to 853 the current degree bound, or a string that can be interpreted 854 as an expression in the algebra (provided that the 855 coefficients are numerical). 856 857 EXAMPLE:: 858 859 sage: F.<t,y,z> = FreeAlgebra(ZZ, implementation='letterplace', degrees=[4,2,3]) 860 861 Conversion of a number:: 862 863 sage: F(3) 864 3 865 866 Interpretation of a string as an algebra element:: 867 868 sage: F('t*y+3*z^2') 869 t*y + 3*z*z 870 871 Conversion from the currently underlying polynomial ring:: 872 873 sage: F.set_degbound(3) 874 sage: P = F.current_ring() 875 sage: F(P.0*P.7*P.11*P.15*P.17*P.23 - 2*P.2*P.7*P.11*P.14*P.19*P.23) 876 t*y - 2*z*z 877 878 Conversion from a graded sub-algebra:: 879 880 sage: G = FreeAlgebra(GF(5), implementation='letterplace', names=['x','y','z','t'], degrees=[1,2,3,4]) 881 sage: G(t*y + 2*y^3 - 4*z^2) # indirect doctest 882 (2)*y*y*y + z*z + t*y 883 884 """ 885 if isinstance(x, basestring): 886 from sage.all import sage_eval 887 return sage_eval(x,locals=self.gens_dict()) 888 try: 889 P = x.parent() 890 except AttributeError: 891 P = None 892 if P is self: 893 (<FreeAlgebraElement_letterplace>x)._poly = self._current_ring((<FreeAlgebraElement_letterplace>x)._poly) 894 return x 895 if isinstance(P, FreeAlgebra_letterplace): 896 self.set_degbound(P.degbound()) 897 Ppoly = (<FreeAlgebra_letterplace>P)._current_ring 898 Gens = self._current_ring.gens() 899 Names = self._current_ring.variable_names() 900 PNames = list(Ppoly.variable_names()) 901 # translate the slack variables 902 PNames[P.ngens(): len(PNames): P.ngens()+1] = list(Names[self.ngens(): len(Names): self.ngens()+1])[:P.degbound()] 903 x = Ppoly.hom([Gens[Names.index(asdf)] for asdf in PNames])(x.letterplace_polynomial()) 904 return FreeAlgebraElement_letterplace(self,self._current_ring(x)) -
new file sage/algebras/letterplace/letterplace_ideal.pyx
diff --git a/sage/algebras/letterplace/letterplace_ideal.pyx b/sage/algebras/letterplace/letterplace_ideal.pyx new file mode 100644
- + 1 ############################################################################### 2 # 3 # Copyright (C) 2011 Simon King <simon.king@uni-jena.de> 4 # Distributed under the terms of the GNU General Public License (GPL), 5 # version 2 or any later version. The full text of the GPL is available at: 6 # http://www.gnu.org/licenses/ 7 # 8 ############################################################################### 9 10 """ 11 Homogeneous ideals of free algebras. 12 13 For twosided ideals and when the base ring is a field, this 14 implementation also provides Groebner bases and ideal containment 15 tests. 16 17 EXAMPLES:: 18 19 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 20 sage: F 21 Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 22 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 23 sage: I 24 Twosided Ideal (x*y + y*z, x*x + x*y - y*x - y*y) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 25 26 One can compute Groebner bases out to a finite degree, can compute normal 27 forms and can test containment in the ideal:: 28 29 sage: I.groebner_basis(degbound=3) 30 Twosided Ideal (y*y*y - y*y*z + y*z*y - y*z*z, y*y*x + y*y*z + y*z*x + y*z*z, x*y + y*z, x*x - y*x - y*y - y*z) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 31 sage: (x*y*z*y*x).normal_form(I) 32 y*z*z*y*z + y*z*z*z*x + y*z*z*z*z 33 sage: x*y*z*y*x - (x*y*z*y*x).normal_form(I) in I 34 True 35 36 AUTHOR: 37 38 - Simon King (2011-03-22): See :trac:`7797`. 39 40 """ 41 42 from sage.rings.noncommutative_ideals import Ideal_nc 43 from sage.libs.singular.function import lib, singular_function 44 from sage.algebras.letterplace.free_algebra_letterplace cimport FreeAlgebra_letterplace 45 from sage.algebras.letterplace.free_algebra_element_letterplace cimport FreeAlgebraElement_letterplace 46 from sage.all import Infinity 47 48 ##################### 49 # Define some singular functions 50 lib("freegb.lib") 51 singular_system=singular_function("system") 52 poly_reduce=singular_function("NF") 53 54 class LetterplaceIdeal(Ideal_nc): 55 """ 56 Graded homogeneous ideals in free algebras. 57 58 In the two-sided case over a field, one can compute Groebner bases 59 up to a degree bound, normal forms of graded homogeneous elements 60 of the free algebra, and ideal containment. 61 62 EXAMPLES:: 63 64 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 65 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 66 sage: I 67 Twosided Ideal (x*y + y*z, x*x + x*y - y*x - y*y) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 68 sage: I.groebner_basis(2) 69 Twosided Ideal (x*y + y*z, x*x - y*x - y*y - y*z) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 70 sage: I.groebner_basis(4) 71 Twosided Ideal (y*z*y*y - y*z*y*z + y*z*z*y - y*z*z*z, y*z*y*x + y*z*y*z + y*z*z*x + y*z*z*z, y*y*z*y - y*y*z*z + y*z*z*y - y*z*z*z, y*y*z*x + y*y*z*z + y*z*z*x + y*z*z*z, y*y*y - y*y*z + y*z*y - y*z*z, y*y*x + y*y*z + y*z*x + y*z*z, x*y + y*z, x*x - y*x - y*y - y*z) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 72 73 Groebner bases are cached. If one has computed a Groebner basis 74 out to a high degree then it will also be returned if a Groebner 75 basis with a lower degree bound is requested:: 76 77 sage: I.groebner_basis(2) 78 Twosided Ideal (y*z*y*y - y*z*y*z + y*z*z*y - y*z*z*z, y*z*y*x + y*z*y*z + y*z*z*x + y*z*z*z, y*y*z*y - y*y*z*z + y*z*z*y - y*z*z*z, y*y*z*x + y*y*z*z + y*z*z*x + y*z*z*z, y*y*y - y*y*z + y*z*y - y*z*z, y*y*x + y*y*z + y*z*x + y*z*z, x*y + y*z, x*x - y*x - y*y - y*z) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 79 80 Of course, the normal form of any element has to satisfy the following:: 81 82 sage: x*y*z*y*x - (x*y*z*y*x).normal_form(I) in I 83 True 84 85 Left and right ideals can be constructed, but only twosided ideals provide 86 Groebner bases:: 87 88 sage: JL = F*[x*y+y*z,x^2+x*y-y*x-y^2]; JL 89 Left Ideal (x*y + y*z, x*x + x*y - y*x - y*y) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 90 sage: JR = [x*y+y*z,x^2+x*y-y*x-y^2]*F; JR 91 Right Ideal (x*y + y*z, x*x + x*y - y*x - y*y) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 92 sage: JR.groebner_basis(2) 93 Traceback (most recent call last): 94 ... 95 TypeError: This ideal is not two-sided. We can only compute two-sided Groebner bases 96 sage: JL.groebner_basis(2) 97 Traceback (most recent call last): 98 ... 99 TypeError: This ideal is not two-sided. We can only compute two-sided Groebner bases 100 101 Also, it is currently not possible to compute a Groebner basis when the base 102 ring is not a field:: 103 104 sage: FZ.<a,b,c> = FreeAlgebra(ZZ, implementation='letterplace') 105 sage: J = FZ*[a^3-b^3]*FZ 106 sage: J.groebner_basis(2) 107 Traceback (most recent call last): 108 ... 109 TypeError: Currently, we can only compute Groebner bases if the ring of coefficients is a field 110 111 The letterplace implementation of free algebras also provides integral degree weights 112 for the generators, and we can compute Groebner bases for twosided graded homogeneous 113 ideals:: 114 115 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace',degrees=[1,2,3]) 116 sage: I = F*[x*y+z-y*x,x*y*z-x^6+y^3]*F 117 sage: I.groebner_basis(Infinity) 118 Twosided Ideal (x*z*z - y*x*x*z - y*x*y*y + y*x*z*x + y*y*y*x + z*x*z + z*y*y - z*z*x, 119 x*y - y*x + z, 120 x*x*x*x*z*y*y + x*x*x*z*y*y*x - x*x*x*z*y*z - x*x*z*y*x*z + x*x*z*y*y*x*x + 121 x*x*z*y*y*y - x*x*z*y*z*x - x*z*y*x*x*z - x*z*y*x*z*x + 122 x*z*y*y*x*x*x + 2*x*z*y*y*y*x - 2*x*z*y*y*z - x*z*y*z*x*x - 123 x*z*y*z*y + y*x*z*x*x*x*x*x - 4*y*x*z*x*x*z - 4*y*x*z*x*z*x + 124 4*y*x*z*y*x*x*x + 3*y*x*z*y*y*x - 4*y*x*z*y*z + y*y*x*x*x*x*z + 125 y*y*x*x*x*z*x - 3*y*y*x*x*z*x*x - y*y*x*x*z*y + 126 5*y*y*x*z*x*x*x + 4*y*y*x*z*y*x - 4*y*y*y*x*x*z + 127 4*y*y*y*x*z*x + 3*y*y*y*y*z + 4*y*y*y*z*x*x + 6*y*y*y*z*y + 128 y*y*z*x*x*x*x + y*y*z*x*z + 7*y*y*z*y*x*x + 7*y*y*z*y*y - 129 7*y*y*z*z*x - y*z*x*x*x*z - y*z*x*x*z*x + 3*y*z*x*z*x*x + 130 y*z*x*z*y + y*z*y*x*x*x*x - 3*y*z*y*x*z + 7*y*z*y*y*x*x + 131 3*y*z*y*y*y - 3*y*z*y*z*x - 5*y*z*z*x*x*x - 4*y*z*z*y*x + 132 4*y*z*z*z - z*y*x*x*x*z - z*y*x*x*z*x - z*y*x*z*x*x - 133 z*y*x*z*y + z*y*y*x*x*x*x - 3*z*y*y*x*z + 3*z*y*y*y*x*x + 134 z*y*y*y*y - 3*z*y*y*z*x - z*y*z*x*x*x - 2*z*y*z*y*x + 135 2*z*y*z*z - z*z*x*x*x*x*x + 4*z*z*x*x*z + 4*z*z*x*z*x - 136 4*z*z*y*x*x*x - 3*z*z*y*y*x + 4*z*z*y*z + 4*z*z*z*x*x + 137 2*z*z*z*y, 138 x*x*x*x*x*z + x*x*x*x*z*x + x*x*x*z*x*x + x*x*z*x*x*x + x*z*x*x*x*x + 139 y*x*z*y - y*y*x*z + y*z*z + z*x*x*x*x*x - z*z*y, 140 x*x*x*x*x*x - y*x*z - y*y*y + z*z) 141 of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 142 143 Again, we can compute normal forms:: 144 145 sage: (z*I.0-I.1).normal_form(I) 146 0 147 sage: (z*I.0-x*y*z).normal_form(I) 148 -y*x*z + z*z 149 150 """ 151 def __init__(self, ring, gens, coerce=True, side = "twosided"): 152 """ 153 INPUT: 154 155 - ``ring``: A free algebra in letterplace implementation. 156 - ``gens``: List, tuple or sequence of generators. 157 - ``coerce`` (optional bool, default ``True``): 158 Shall ``gens`` be coerced first? 159 - ``side``: optional string, one of ``"twosided"`` (default), 160 ``"left"`` or ``"right"``. Determines whether the ideal 161 is a left, right or twosided ideal. Groebner bases or 162 only supported in the twosided case. 163 164 TEST:: 165 166 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 167 sage: from sage.algebras.letterplace.letterplace_ideal import LetterplaceIdeal 168 sage: LetterplaceIdeal(F,x) 169 Twosided Ideal (x) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 170 sage: LetterplaceIdeal(F,[x,y],side='left') 171 Left Ideal (x, y) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 172 173 It is not correctly detected that this class inherits from an 174 extension class. Therefore, we have to skip one item of the 175 test suite:: 176 177 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 178 sage: TestSuite(I).run(skip=['_test_category'],verbose=True) 179 running ._test_eq() . . . pass 180 running ._test_not_implemented_methods() . . . pass 181 running ._test_pickling() . . . pass 182 183 """ 184 Ideal_nc.__init__(self, ring, gens, coerce=coerce, side=side) 185 self.__GB = self 186 self.__uptodeg = 0 187 def groebner_basis(self, degbound=None): 188 """ 189 Twosided Groebner basis with degree bound. 190 191 INPUT: 192 193 - ``degbound`` (optional integer, or Infinity): If it is provided, 194 a Groebner basis at least out to that degree is returned. By 195 default, the current degree bound of the underlying ring is used. 196 197 ASSUMPTIONS: 198 199 Currently, we can only compute Groebner bases for twosided 200 ideals, and the ring of coefficients must be a field. A 201 `TypeError` is raised if one of these conditions is violated. 202 203 NOTES: 204 205 - The result is cached. The same Groebner basis is returned 206 if a smaller degree bound than the known one is requested. 207 - If the degree bound Infinity is requested, it is attempted to 208 compute a complete Groebner basis. But we can not guarantee 209 that the computation will terminate, since not all twosided 210 homogeneous ideals of a free algebra have a finite Groebner 211 basis. 212 213 EXAMPLES:: 214 215 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 216 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 217 218 Since `F` was cached and since its degree bound can not be 219 decreased, it may happen that, as a side effect of other tests, 220 it already has a degree bound bigger than 3. So, we can not 221 test against the output of ``I.groebner_basis()``:: 222 223 sage: F.set_degbound(3) 224 sage: I.groebner_basis() # not tested 225 Twosided Ideal (y*y*y - y*y*z + y*z*y - y*z*z, y*y*x + y*y*z + y*z*x + y*z*z, x*y + y*z, x*x - y*x - y*y - y*z) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 226 sage: I.groebner_basis(4) 227 Twosided Ideal (y*z*y*y - y*z*y*z + y*z*z*y - y*z*z*z, y*z*y*x + y*z*y*z + y*z*z*x + y*z*z*z, y*y*z*y - y*y*z*z + y*z*z*y - y*z*z*z, y*y*z*x + y*y*z*z + y*z*z*x + y*z*z*z, y*y*y - y*y*z + y*z*y - y*z*z, y*y*x + y*y*z + y*z*x + y*z*z, x*y + y*z, x*x - y*x - y*y - y*z) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 228 sage: I.groebner_basis(2) is I.groebner_basis(4) 229 True 230 sage: G = I.groebner_basis(4) 231 sage: G.groebner_basis(3) is G 232 True 233 234 If a finite complete Groebner basis exists, we can compute 235 it as follows:: 236 237 sage: I = F*[x*y-y*x,x*z-z*x,y*z-z*y,x^2*y-z^3,x*y^2+z*x^2]*F 238 sage: I.groebner_basis(Infinity) 239 Twosided Ideal (z*z*z*y*y + z*z*z*z*x, z*x*x*x + z*z*z*y, y*z - z*y, y*y*x + z*x*x, y*x*x - z*z*z, x*z - z*x, x*y - y*x) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 240 241 Since the commutators of the generators are contained in the ideal, 242 we can verify the above result by a computation in a polynomial ring 243 in negative lexicographic order:: 244 245 sage: P.<c,b,a> = PolynomialRing(QQ,order='neglex') 246 sage: J = P*[a^2*b-c^3,a*b^2+c*a^2] 247 sage: J.groebner_basis() 248 [b*a^2 - c^3, b^2*a + c*a^2, c*a^3 + c^3*b, c^3*b^2 + c^4*a] 249 250 Aparently, the results are compatible, by sending `a` to `x`, `b` 251 to `y` and `c` to `z`. 252 253 """ 254 cdef FreeAlgebra_letterplace A = self.ring() 255 cdef FreeAlgebraElement_letterplace x 256 if degbound is None: 257 degbound = A.degbound() 258 if self.__uptodeg >= degbound: 259 return self.__GB 260 if not A.base().is_field(): 261 raise TypeError, "Currently, we can only compute Groebner bases if the ring of coefficients is a field" 262 if self.side()!='twosided': 263 raise TypeError, "This ideal is not two-sided. We can only compute two-sided Groebner bases" 264 if degbound == Infinity: 265 while self.__uptodeg<Infinity: 266 test_bound = 2*max([x._poly.degree() for x in self.__GB.gens()]) 267 self.groebner_basis(test_bound) 268 return self.__GB 269 # Set the options required by letterplace 270 from sage.libs.singular.option import LibSingularOptions 271 libsingular_options = LibSingularOptions() 272 bck = (libsingular_options['redTail'],libsingular_options['redSB']) 273 libsingular_options['redTail'] = True 274 libsingular_options['redSB'] = True 275 A.set_degbound(degbound) 276 P = A._current_ring 277 out = [FreeAlgebraElement_letterplace(A,X,check=False) for X in 278 singular_system("freegb",P.ideal([x._poly for x in self.__GB.gens()]), 279 degbound,A.__ngens, ring = P)] 280 libsingular_options['redTail'] = bck[0] 281 libsingular_options['redSB'] = bck[1] 282 self.__GB = A.ideal(out,side='twosided',coerce=False) 283 if degbound >= 2*max([x._poly.degree() for x in out]): 284 degbound = Infinity 285 self.__uptodeg = degbound 286 self.__GB.__uptodeg = degbound 287 return self.__GB 288 289 def __contains__(self,x): 290 """ 291 The containment test is based on a normal form computation. 292 293 EXAMPLES:: 294 295 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 296 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 297 sage: x*I.0-I.1*y+I.0*y in I # indirect doctest 298 True 299 sage: 1 in I 300 False 301 302 """ 303 R = self.ring() 304 return (x in R) and R(x).normal_form(self).is_zero() 305 306 def reduce(self, G): 307 """ 308 Reduction of this ideal by another ideal, 309 or normal form of an algebra element with respect to this ideal. 310 311 INPUT: 312 313 - ``G``: A list or tuple of elements, an ideal, 314 the ambient algebra, or a single element. 315 316 OUTPUT: 317 318 - The normal form of ``G`` with respect to this ideal, if 319 ``G`` is an element of the algebra. 320 - The reduction of this ideal by the elements resp. generators 321 of ``G``, if ``G`` is a list, tuple or ideal. 322 - The zero ideal, if ``G`` is the algebra containing this ideal. 323 324 EXAMPLES:: 325 326 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 327 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 328 sage: I.reduce(F) 329 Twosided Ideal (0) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 330 sage: I.reduce(x^3) 331 -y*z*x - y*z*y - y*z*z 332 sage: I.reduce([x*y]) 333 Twosided Ideal (y*z, x*x - y*x - y*y) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 334 sage: I.reduce(F*[x^2+x*y,y^2+y*z]*F) 335 Twosided Ideal (x*y + y*z, -y*x + y*z) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field 336 337 """ 338 P = self.ring() 339 if not isinstance(G,(list,tuple)): 340 if G==P: 341 return P.ideal([P.zero_element()]) 342 if G in P: 343 return G.normal_form(self) 344 G = G.gens() 345 C = P.current_ring() 346 sI = C.ideal([C(X.letterplace_polynomial()) for X in self.gens()], coerce=False) 347 selfdeg = max([x.degree() for x in sI.gens()]) 348 gI = P._reductor_(G, selfdeg) 349 from sage.libs.singular.option import LibSingularOptions 350 libsingular_options = LibSingularOptions() 351 bck = (libsingular_options['redTail'],libsingular_options['redSB']) 352 libsingular_options['redTail'] = True 353 libsingular_options['redSB'] = True 354 sI = poly_reduce(sI,gI, ring=C, attributes={gI:{"isSB":1}}) 355 libsingular_options['redTail'] = bck[0] 356 libsingular_options['redSB'] = bck[1] 357 return P.ideal([FreeAlgebraElement_letterplace(P,x,check=False) for x in sI], coerce=False) -
sage/categories/rings.py
diff --git a/sage/categories/rings.py b/sage/categories/rings.py
a b 108 108 rings also inherits from the base class of 109 109 rings. Therefore, we implemented a ``__mul__`` 110 110 method for parents, that calls a ``_mul_`` 111 method implemented here. See trac ticket #11068.111 method implemented here. See :trac:`7797`. 112 112 113 113 INPUT: 114 114 … … 190 190 The code is copied from the base class of rings. 191 191 This is since there are rings that do not inherit 192 192 from that class, such as matrix algebras. See 193 trac ticket #11068.193 :trac:`7797`. 194 194 195 195 EXAMPLE:: 196 196 … … 267 267 :class:`~sage.rings.ring.Ring`. This is 268 268 because there are rings that do not inherit 269 269 from that class, such as matrix algebras. 270 See trac ticket #11068.270 See :trac:`7797`. 271 271 272 272 INPUT: 273 273 … … 439 439 - ``names``: a list of strings to be used as names 440 440 for the variables in the quotient ring. 441 441 442 EXAMPLES: :442 EXAMPLES: 443 443 444 sage: F.<x,y,z> = FreeAlgebra(QQ, 3) 445 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 444 Usually, a ring inherits a method :meth:`sage.rings.ring.Ring.quotient`. 445 So, we need a bit of effort to make the following example work with the 446 category framework:: 447 448 sage: F.<x,y,z> = FreeAlgebra(QQ) 449 sage: from sage.rings.noncommutative_ideals import Ideal_nc 450 sage: class PowerIdeal(Ideal_nc): 451 ... def __init__(self, R, n): 452 ... self._power = n 453 ... self._power = n 454 ... Ideal_nc.__init__(self,R,[R.prod(m) for m in CartesianProduct(*[R.gens()]*n)]) 455 ... def reduce(self,x): 456 ... R = self.ring() 457 ... return add([c*R(m) for c,m in x if len(m)<self._power],R(0)) 458 ... 459 sage: I = PowerIdeal(F,3) 446 460 sage: Q = Rings().parent_class.quotient(F,I); Q 447 Quotient of Free Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x *y + y*z, x^2 + x*y - y*x - y^2)461 Quotient of Free Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x^3, x^2*y, x^2*z, x*y*x, x*y^2, x*y*z, x*z*x, x*z*y, x*z^2, y*x^2, y*x*y, y*x*z, y^2*x, y^3, y^2*z, y*z*x, y*z*y, y*z^2, z*x^2, z*x*y, z*x*z, z*y*x, z*y^2, z*y*z, z^2*x, z^2*y, z^3) 448 462 sage: Q.0 449 463 xbar 450 464 sage: Q.1 451 465 ybar 452 466 sage: Q.2 453 467 zbar 468 sage: Q.0*Q.1 469 xbar*ybar 470 sage: Q.0*Q.1*Q.0 471 0 454 472 455 473 """ 456 474 from sage.rings.quotient_ring import QuotientRing -
sage/rings/noncommutative_ideals.pyx
diff --git a/sage/rings/noncommutative_ideals.pyx b/sage/rings/noncommutative_ideals.pyx
a b 12 12 13 13 AUTHOR: 14 14 15 - Simon King (2011-03-2 8), <simon.king@uni-jena.de>: Trac ticket #11068.15 - Simon King (2011-03-21), <simon.king@uni-jena.de>, :trac:`7797`. 16 16 17 17 EXAMPLES:: 18 18 … … 39 39 ) 40 40 of Full MatrixSpace of 2 by 2 dense matrices over Integer Ring 41 41 42 See :mod:`~sage.algebras.letterplace.letterplace_ideal` for a more 43 elaborate implementation in the special case of ideals in free 44 algebras. 45 42 46 TEST:: 43 47 44 48 sage: A = SteenrodAlgebra(2) … … 137 141 Generic non-commutative ideal. 138 142 139 143 All fancy stuff such as the computation of Groebner bases must be 140 implemented in sub-classes. 144 implemented in sub-classes. See :class:`~sage.algebras.letterplace.letterplace_ideal.LetterplaceIdeal` 145 for an example. 141 146 142 147 EXAMPLE:: 143 148 -
sage/rings/quotient_ring.py
diff --git a/sage/rings/quotient_ring.py b/sage/rings/quotient_ring.py
a b 21 21 provides a ``reduce`` method so that ``I.reduce(x)`` is the normal 22 22 form of an element `x` with respect to `I` (i.e., we have 23 23 ``I.reduce(x)==I.reduce(y)`` if `x-y\\in I`, and 24 ``x-I.reduce(x) in I``). It is planned (trac ticket #7797) to 25 provide this for the case of homogeneous twosided ideals in free 26 algebras. By now, we only have the following toy example:: 24 ``x-I.reduce(x) in I``). Here is a toy example:: 27 25 28 26 sage: from sage.rings.noncommutative_ideals import Ideal_nc 29 27 sage: class PowerIdeal(Ideal_nc): … … 75 73 sage: (a+b+2)^4 76 74 16 + 32*a + 32*b 77 75 76 Since trac ticket #7797, there is an implementation of free algebras 77 based on Singular's implementation of the Letterplace Algebra. Our 78 letterplace wrapper allows to provide the above toy example more 79 easily:: 80 81 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 82 sage: Q3 = F.quo(F*[F.prod(m) for m in CartesianProduct(*[F.gens()]*3)]*F) 83 sage: Q3 84 Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*x*x, x*x*y, x*x*z, x*y*x, x*y*y, x*y*z, x*z*x, x*z*y, x*z*z, y*x*x, y*x*y, y*x*z, y*y*x, y*y*y, y*y*z, y*z*x, y*z*y, y*z*z, z*x*x, z*x*y, z*x*z, z*y*x, z*y*y, z*y*z, z*z*x, z*z*y, z*z*z) 85 sage: Q3.0*Q3.1-Q3.1*Q3.0 86 xbar*ybar - ybar*xbar 87 sage: Q3.0*(Q3.1*Q3.2)-(Q3.1*Q3.2)*Q3.0 88 0 89 sage: Q2 = F.quo(F*[F.prod(m) for m in CartesianProduct(*[F.gens()]*2)]*F) 90 sage: Q2.is_commutative() 91 True 92 78 93 """ 79 94 80 95 ########################################################################### … … 209 224 sage: R.quotient(I) 210 225 Ring of integers modulo 2 211 226 227 Here is an example of the quotient of a free algebra by a 228 twosided homogeneous ideal (see :trac:`7797`):: 229 230 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 231 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 232 sage: Q.<a,b,c> = F.quo(I); Q 233 Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) 234 sage: a*b 235 -b*c 236 sage: a^3 237 -b*c*a - b*c*b - b*c*c 238 sage: J = Q*[a^3-b^3]*Q 239 sage: R.<i,j,k> = Q.quo(J); R 240 Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (-y*y*z - y*z*x - 2*y*z*z, x*y + y*z, x*x + x*y - y*x - y*y) 241 sage: i^3 242 -j*k*i - j*k*j - j*k*k 243 sage: j^3 244 -j*k*i - j*k*j - j*k*k 245 212 246 """ 213 247 # 1. Not all rings inherit from the base class of rings. 214 248 # 2. We want to support quotients of free algebras by homogeneous two-sided ideals. … … 269 303 sage: is_QuotientRing(R) 270 304 False 271 305 306 :: 307 308 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 309 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 310 sage: Q = F.quo(I) 311 sage: is_QuotientRing(Q) 312 True 313 sage: is_QuotientRing(F) 314 False 315 272 316 """ 273 317 return isinstance(x, QuotientRing_nc) 274 318 … … 283 327 """ 284 328 The quotient ring of `R` by a twosided ideal `I`. 285 329 286 This base class is for rings that do not inherit from :class:`~sage.rings.ring.CommutativeRing`. 287 Real life examples will be available with trac ticket #7797. 330 EXAMPLES: 331 332 This class is for rings that do not inherit from :class:`~sage.rings.ring.CommutativeRing`. 333 Here is a quotient of a free algebra by a twosided homogeneous ideal:: 334 335 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 336 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 337 sage: Q.<a,b,c> = F.quo(I); Q 338 Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) 339 sage: a*b 340 -b*c 341 sage: a^3 342 -b*c*a - b*c*b - b*c*c 343 344 A quotient of a quotient is just the quotient of the original top 345 ring by the sum of two ideals:: 346 347 sage: J = Q*[a^3-b^3]*Q 348 sage: R.<i,j,k> = Q.quo(J); R 349 Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (-y*y*z - y*z*x - 2*y*z*z, x*y + y*z, x*x + x*y - y*x - y*y) 350 sage: i^3 351 -j*k*i - j*k*j - j*k*k 352 sage: j^3 353 -j*k*i - j*k*j - j*k*k 288 354 289 355 For rings that *do* inherit from :class:`~sage.rings.ring.CommutativeRing`, we provide 290 356 a subclass :class:`QuotientRing_generic`, for backwards compatibility. … … 305 371 sage: S(0) == a^2 + b^2 306 372 True 307 373 308 A quotient of a quotient is just the quotient of the original top374 Again, a quotient of a quotient is just the quotient of the original top 309 375 ring by the sum of two ideals. 310 376 311 377 :: … … 328 394 - ``R`` - a ring. 329 395 - ``I`` - a twosided ideal of `R`. 330 396 - ``names`` - a list of generator names. 331 397 398 EXAMPLES:: 399 400 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 401 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 402 sage: Q.<a,b,c> = F.quo(I); Q 403 Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) 404 sage: a*b 405 -b*c 406 sage: a^3 407 -b*c*a - b*c*b - b*c*c 408 332 409 """ 333 410 if R not in _Rings: 334 411 raise TypeError, "The first argument must be a ring, but %s is not"%R … … 365 442 sage: I = R.ideal([4 + 3*x + x^2, 1 + x^2]) 366 443 sage: R.quotient_ring(I).construction() 367 444 (QuotientFunctor, Univariate Polynomial Ring in x over Integer Ring) 445 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 446 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 447 sage: Q = F.quo(I) 448 sage: Q.construction() 449 (QuotientFunctor, Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field) 368 450 369 451 TESTS:: 370 452 … … 422 504 423 505 AUTHOR: 424 506 425 - Simon King (2011-03-23): See trac ticket #11068.507 - Simon King (2011-03-23): See :trac:`7797`. 426 508 427 509 EXAMPLES: 428 510 … … 432 514 sage: P.quo(P.random_element()).is_commutative() 433 515 True 434 516 435 The non-commutative case is more interesting, but it 436 will only be available once trac ticket #7797 is merged. 517 The non-commutative case is more interesting:: 518 519 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 520 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 521 sage: Q = F.quo(I) 522 sage: Q.is_commutative() 523 False 524 sage: Q.1*Q.2==Q.2*Q.1 525 False 526 527 In the next example, the generators apparently commute:: 528 529 sage: J = F*[x*y-y*x,x*z-z*x,y*z-z*y,x^3-y^3]*F 530 sage: R = F.quo(J) 531 sage: R.is_commutative() 532 True 437 533 438 534 """ 439 535 try: -
sage/rings/quotient_ring_element.py
diff --git a/sage/rings/quotient_ring_element.py b/sage/rings/quotient_ring_element.py
a b 533 533 0 534 534 sage: a.__cmp__(b) 535 535 1 536 537 See :trac:`7797`: 538 539 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 540 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 541 sage: Q = F.quo(I) 542 sage: Q.0^4 # indirect doctest 543 ybar*zbar*zbar*xbar + ybar*zbar*zbar*ybar + ybar*zbar*zbar*zbar 544 536 545 """ 537 546 #if self.__rep == other.__rep or ((self.__rep - other.__rep) in self.parent().defining_ideal()): 538 547 # return 0 -
sage/rings/ring.pyx
diff --git a/sage/rings/ring.pyx b/sage/rings/ring.pyx
a b 409 409 sage: Q = sage.rings.ring.Ring.quotient(F,I) 410 410 sage: Q.ideal_monoid() 411 411 Monoid of ideals of Quotient of Free Algebra on 3 generators (x, y, z) over Integer Ring by the ideal (x*y + y*z, x^2 + x*y - y*x - y^2) 412 sage: F.<x,y,z> = FreeAlgebra(ZZ, implementation='letterplace') 413 sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F 414 sage: Q = F.quo(I) 415 sage: Q.ideal_monoid() 416 Monoid of ideals of Quotient of Free Associative Unital Algebra on 3 generators (x, y, z) over Integer Ring by the ideal (x*y + y*z, x*x + x*y - y*x - y*y) 412 417 413 418 """ 414 419 if self.__ideal_monoid is not None: … … 536 541 sage: (x+y,z+y^3)*R 537 542 Ideal (x + y, y^3 + z) of Multivariate Polynomial Ring in x, y, z over Finite Field of size 7 538 543 539 The following was implemented in trac ticket #11068::544 The following was implemented in :trac:`7797`:: 540 545 541 546 sage: A = SteenrodAlgebra(2) 542 547 sage: A*[A.1+A.2,A.1^2] … … 609 614 sage: RR._ideal_class_() 610 615 <class 'sage.rings.ideal.Ideal_pid'> 611 616 612 Since #11068, non-commutative rings have ideals as well::617 Since :trac:`7797`, non-commutative rings have ideals as well:: 613 618 614 619 sage: A = SteenrodAlgebra(2) 615 620 sage: A._ideal_class_() -
sage/structure/parent.pyx
diff --git a/sage/structure/parent.pyx b/sage/structure/parent.pyx
a b 814 814 is because ``__mul__`` can not be implemented via inheritance 815 815 from the parent methods of the category, but ``_mul_`` can 816 816 be inherited. This is, e.g., used when creating twosided 817 ideals of matrix algebras. See trac ticket #11068.817 ideals of matrix algebras. See :trac:`7797`. 818 818 819 819 EXAMPLE:: 820 820 821 sage: F.<x,y,z> = FreeAlgebra(QQ, implementation='letterplace') 821 822 sage: MS = MatrixSpace(QQ,2,2) 822 823 823 824 This matrix space is in fact an algebra, and in particular -
setup.py
diff --git a/setup.py b/setup.py
a b 855 855 packages = ['sage', 856 856 857 857 'sage.algebras', 858 'sage.algebras.letterplace', 858 859 'sage.algebras.quatalg', 859 860 'sage.algebras.steenrod', 860 861
