Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/algebras/free_algebra.py
8818 views
1
"""
2
Free algebras
3
4
AUTHORS:
5
6
- David Kohel (2005-09)
7
8
- William Stein (2006-11-01): add all doctests; implemented many
9
things.
10
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.
16
17
EXAMPLES::
18
19
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
20
sage: F.base_ring()
21
Integer Ring
22
sage: G = FreeAlgebra(F, 2, 'm,n'); G
23
Free Algebra on 2 generators (m, n) over Free Algebra on 3 generators (x, y, z) over Integer Ring
24
sage: G.base_ring()
25
Free Algebra on 3 generators (x, y, z) over Integer Ring
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
61
TESTS::
62
63
sage: F = FreeAlgebra(GF(5),3,'x')
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
71
72
::
73
74
sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
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
82
83
::
84
85
sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y'])
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
93
94
::
95
96
sage: F = FreeAlgebra(GF(5),3, 'abc')
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
104
105
::
106
107
sage: F = FreeAlgebra(FreeAlgebra(ZZ,2,'ab'), 2, 'x')
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
119
120
"""
121
122
#*****************************************************************************
123
# Copyright (C) 2005 David Kohel <[email protected]>
124
# Copyright (C) 2005,2006 William Stein <[email protected]>
125
# Copyright (C) 2011 Simon King <[email protected]>
126
#
127
# Distributed under the terms of the GNU General Public License (GPL)
128
# http://www.gnu.org/licenses/
129
#*****************************************************************************
130
131
from sage.rings.ring import Ring
132
133
from sage.monoids.free_monoid import FreeMonoid
134
from sage.monoids.free_monoid_element import FreeMonoidElement
135
136
from sage.algebras.algebra import Algebra
137
from sage.algebras.free_algebra_element import FreeAlgebraElement
138
139
import sage.structure.parent_gens
140
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
from sage.categories.algebras_with_basis import AlgebrasWithBasis
145
from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModuleElement
146
from sage.combinat.words.word import Word
147
from sage.combinat.lyndon_word import LyndonWords
148
149
class FreeAlgebraFactory(UniqueFactory):
150
"""
151
A constructor of free algebras.
152
153
See :mod:`~sage.algebras.free_algebra` for examples and corner cases.
154
155
EXAMPLES::
156
157
sage: FreeAlgebra(GF(5),3,'x')
158
Free Algebra on 3 generators (x0, x1, x2) over Finite Field of size 5
159
sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
160
sage: (x+y+z)^2
161
x^2 + x*y + x*z + y*x + y^2 + y*z + z*x + z*y + z^2
162
sage: FreeAlgebra(GF(5),3, 'xx, zba, Y')
163
Free Algebra on 3 generators (xx, zba, Y) over Finite Field of size 5
164
sage: FreeAlgebra(GF(5),3, 'abc')
165
Free Algebra on 3 generators (a, b, c) over Finite Field of size 5
166
sage: FreeAlgebra(GF(5),1, 'z')
167
Free Algebra on 1 generators (z,) over Finite Field of size 5
168
sage: FreeAlgebra(GF(5),1, ['alpha'])
169
Free Algebra on 1 generators (alpha,) over Finite Field of size 5
170
sage: FreeAlgebra(FreeAlgebra(ZZ,1,'a'), 2, 'x')
171
Free Algebra on 2 generators (x0, x1) over Free Algebra on 1 generators (a,) over Integer Ring
172
173
Free algebras are globally unique::
174
175
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
176
sage: G = FreeAlgebra(ZZ,3,'x,y,z')
177
sage: F is G
178
True
179
sage: F.<x,y,z> = FreeAlgebra(GF(5),3) # indirect doctest
180
sage: F is loads(dumps(F))
181
True
182
sage: F is FreeAlgebra(GF(5),['x','y','z'])
183
True
184
sage: copy(F) is F is loads(dumps(F))
185
True
186
sage: TestSuite(F).run()
187
188
By :trac:`7797`, we provide a different implementation of free
189
algebras, based on Singular's "letterplace rings". Our letterplace
190
wrapper allows for chosing positive integral degree weights for the
191
generators of the free algebra. However, only (weighted) homogenous
192
elements are supported. Of course, isomorphic algebras in different
193
implementations are not identical::
194
195
sage: G = FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace')
196
sage: F == G
197
False
198
sage: G is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace')
199
True
200
sage: copy(G) is G is loads(dumps(G))
201
True
202
sage: TestSuite(G).run()
203
204
::
205
206
sage: H = FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace', degrees=[1,2,3])
207
sage: F != H != G
208
True
209
sage: H is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace', degrees=[1,2,3])
210
True
211
sage: copy(H) is H is loads(dumps(H))
212
True
213
sage: TestSuite(H).run()
214
215
Free algebras commute with their base ring.
216
::
217
218
sage: K.<a,b> = FreeAlgebra(QQ,2)
219
sage: K.is_commutative()
220
False
221
sage: L.<c> = FreeAlgebra(K,1)
222
sage: L.is_commutative()
223
False
224
sage: s = a*b^2 * c^3; s
225
a*b^2*c^3
226
sage: parent(s)
227
Free Algebra on 1 generators (c,) over Free Algebra on 2 generators (a, b) over Rational Field
228
sage: c^3 * a * b^2
229
a*b^2*c^3
230
"""
231
def create_key(self,base_ring, arg1=None, arg2=None,
232
sparse=False, order='degrevlex',
233
names=None, name=None,
234
implementation=None, degrees=None):
235
"""
236
Create the key under which a free algebra is stored.
237
238
TESTS::
239
240
sage: FreeAlgebra.create_key(GF(5),['x','y','z'])
241
(Finite Field of size 5, ('x', 'y', 'z'))
242
sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3)
243
(Finite Field of size 5, ('x', 'y', 'z'))
244
sage: FreeAlgebra.create_key(GF(5),3,'xyz')
245
(Finite Field of size 5, ('x', 'y', 'z'))
246
sage: FreeAlgebra.create_key(GF(5),['x','y','z'], implementation='letterplace')
247
(Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
248
sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3, implementation='letterplace')
249
(Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
250
sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace')
251
(Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,)
252
sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace', degrees=[1,2,3])
253
((1, 2, 3), Multivariate Polynomial Ring in x, y, z, x_ over Finite Field of size 5)
254
255
"""
256
if arg1 is None and arg2 is None and names is None:
257
# this is used for pickling
258
if degrees is None:
259
return (base_ring,)
260
return tuple(degrees),base_ring
261
PolRing = None
262
# test if we can use libSingular/letterplace
263
if implementation is not None and implementation != 'generic':
264
try:
265
PolRing = PolynomialRing(base_ring, arg1, arg2,
266
sparse=sparse, order=order,
267
names=names, name=name,
268
implementation=implementation if implementation!='letterplace' else None)
269
if not isinstance(PolRing,MPolynomialRing_libsingular):
270
if PolRing.ngens() == 1:
271
PolRing = PolynomialRing(base_ring,1,PolRing.variable_names())
272
if not isinstance(PolRing,MPolynomialRing_libsingular):
273
raise TypeError
274
else:
275
raise TypeError
276
except (TypeError, NotImplementedError),msg:
277
raise NotImplementedError, "The letterplace implementation is not available for the free algebra you requested"
278
if PolRing is not None:
279
if degrees is None:
280
return (PolRing,)
281
from sage.all import TermOrder
282
T = PolRing.term_order()+TermOrder('lex',1)
283
varnames = list(PolRing.variable_names())
284
newname = 'x'
285
while newname in varnames:
286
newname += '_'
287
varnames.append(newname)
288
return tuple(degrees),PolynomialRing(PolRing.base(), varnames,
289
sparse=sparse, order=T,
290
implementation=implementation if implementation!='letterplace' else None)
291
# normalise the generator names
292
from sage.all import Integer
293
if isinstance(arg1, (int, long, Integer)):
294
arg1, arg2 = arg2, arg1
295
if not names is None:
296
arg1 = names
297
elif not name is None:
298
arg1 = name
299
if arg2 is None:
300
arg2 = len(arg1)
301
names = sage.structure.parent_gens.normalize_names(arg2,arg1)
302
return base_ring, names
303
304
def create_object(self, version, key):
305
"""
306
Construct the free algebra that belongs to a unique key.
307
308
NOTE:
309
310
Of course, that method should not be called directly,
311
since it does not use the cache of free algebras.
312
313
TESTS::
314
315
sage: FreeAlgebra.create_object('4.7.1', (QQ['x','y'],))
316
Free Associative Unital Algebra on 2 generators (x, y) over Rational Field
317
sage: FreeAlgebra.create_object('4.7.1', (QQ['x','y'],)) is FreeAlgebra(QQ,['x','y'])
318
False
319
320
"""
321
if len(key)==1:
322
from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace
323
return FreeAlgebra_letterplace(key[0])
324
if isinstance(key[0],tuple):
325
from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace
326
return FreeAlgebra_letterplace(key[1],degrees=key[0])
327
return FreeAlgebra_generic(key[0],len(key[1]),key[1])
328
329
FreeAlgebra = FreeAlgebraFactory('FreeAlgebra')
330
331
332
def is_FreeAlgebra(x):
333
"""
334
Return True if x is a free algebra; otherwise, return False.
335
336
EXAMPLES::
337
338
sage: from sage.algebras.free_algebra import is_FreeAlgebra
339
sage: is_FreeAlgebra(5)
340
False
341
sage: is_FreeAlgebra(ZZ)
342
False
343
sage: is_FreeAlgebra(FreeAlgebra(ZZ,100,'x'))
344
True
345
sage: is_FreeAlgebra(FreeAlgebra(ZZ,10,'x',implementation='letterplace'))
346
True
347
sage: is_FreeAlgebra(FreeAlgebra(ZZ,10,'x',implementation='letterplace', degrees=range(1,11)))
348
True
349
350
"""
351
from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace
352
return isinstance(x, (FreeAlgebra_generic,FreeAlgebra_letterplace))
353
354
355
class FreeAlgebra_generic(Algebra):
356
"""
357
The free algebra on `n` generators over a base ring.
358
359
EXAMPLES::
360
361
sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F
362
Free Algebra on 3 generators (x, y, z) over Rational Field
363
sage: mul(F.gens())
364
x*y*z
365
sage: mul([ F.gen(i%3) for i in range(12) ])
366
x*y*z*x*y*z*x*y*z*x*y*z
367
sage: mul([ F.gen(i%3) for i in range(12) ]) + mul([ F.gen(i%2) for i in range(12) ])
368
x*y*x*y*x*y*x*y*x*y*x*y + x*y*z*x*y*z*x*y*z*x*y*z
369
sage: (2 + x*z + x^2)^2 + (x - y)^2
370
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
371
372
TESTS:
373
374
Free algebras commute with their base ring.
375
::
376
377
sage: K.<a,b> = FreeAlgebra(QQ)
378
sage: K.is_commutative()
379
False
380
sage: L.<c,d> = FreeAlgebra(K)
381
sage: L.is_commutative()
382
False
383
sage: s = a*b^2 * c^3; s
384
a*b^2*c^3
385
sage: parent(s)
386
Free Algebra on 2 generators (c, d) over Free Algebra on 2 generators (a, b) over Rational Field
387
sage: c^3 * a * b^2
388
a*b^2*c^3
389
390
"""
391
Element = FreeAlgebraElement
392
def __init__(self, R, n, names):
393
"""
394
The free algebra on `n` generators over a base ring.
395
396
INPUT:
397
398
- ``R`` - ring
399
- ``n`` - an integer
400
- ``names`` - generator names
401
402
EXAMPLES::
403
404
sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctet
405
Free Algebra on 3 generators (x, y, z) over Rational Field
406
407
TEST:
408
409
Note that the following is *not* the recommended way to create
410
a free algebra.
411
::
412
413
sage: from sage.algebras.free_algebra import FreeAlgebra_generic
414
sage: FreeAlgebra_generic(ZZ,3,'abc')
415
Free Algebra on 3 generators (a, b, c) over Integer Ring
416
417
"""
418
if not isinstance(R, Ring):
419
raise TypeError("Argument R must be a ring.")
420
self.__ngens = n
421
#sage.structure.parent_gens.ParentWithGens.__init__(self, R, names)
422
self._basis_keys = FreeMonoid(n, names=names)
423
Algebra.__init__(self, R, names, category=AlgebrasWithBasis(R))
424
425
def one_basis(self):
426
"""
427
Return the index of the basis element `1`.
428
429
EXAMPLES::
430
431
sage: F = FreeAlgebra(QQ, 2, 'x,y')
432
sage: F.one_basis()
433
1
434
sage: F.one_basis().parent()
435
Free monoid on 2 generators (x, y)
436
"""
437
return self._basis_keys.one()
438
439
# Needed for the category AlgebrasWithBasis (but not for Algebras)
440
def term(self, index, coeff=None):
441
"""
442
Construct a term of ``self``.
443
444
INPUT:
445
446
- ``index`` -- the index of the basis element
447
- ``coeff`` -- (default: 1) an element of the coefficient ring
448
449
EXAMPLES::
450
451
sage: M.<x,y> = FreeMonoid(2)
452
sage: F = FreeAlgebra(QQ, 2, 'x,y')
453
sage: F.term(x*x*y)
454
x^2*y
455
sage: F.term(y^3*x*y, 4)
456
4*y^3*x*y
457
sage: F.term(M.one(), 2)
458
2
459
460
TESTS:
461
462
Check to make sure that a coefficient of 0 is properly handled::
463
464
sage: list(F.term(M.one(), 0))
465
[]
466
"""
467
if coeff is None:
468
coeff = self.base_ring().one()
469
if coeff == 0:
470
return self.element_class(self, {})
471
return self.element_class(self, {index: coeff})
472
473
def is_field(self, proof = True):
474
"""
475
Return True if this Free Algebra is a field, which is only if the
476
base ring is a field and there are no generators
477
478
EXAMPLES::
479
480
sage: A=FreeAlgebra(QQ,0,'')
481
sage: A.is_field()
482
True
483
sage: A=FreeAlgebra(QQ,1,'x')
484
sage: A.is_field()
485
False
486
"""
487
if self.__ngens == 0:
488
return self.base_ring().is_field(proof)
489
return False
490
491
def is_commutative(self):
492
"""
493
Return True if this free algebra is commutative.
494
495
EXAMPLES::
496
497
sage: R.<x> = FreeAlgebra(QQ,1)
498
sage: R.is_commutative()
499
True
500
sage: R.<x,y> = FreeAlgebra(QQ,2)
501
sage: R.is_commutative()
502
False
503
"""
504
return self.__ngens <= 1 and self.base_ring().is_commutative()
505
506
def __cmp__(self, other):
507
"""
508
Two free algebras are considered the same if they have the same
509
base ring, number of generators and variable names, and the same
510
implementation.
511
512
EXAMPLES::
513
514
sage: F = FreeAlgebra(QQ,3,'x')
515
sage: F == FreeAlgebra(QQ,3,'x')
516
True
517
sage: F is FreeAlgebra(QQ,3,'x')
518
True
519
sage: F == FreeAlgebra(ZZ,3,'x')
520
False
521
sage: F == FreeAlgebra(QQ,4,'x')
522
False
523
sage: F == FreeAlgebra(QQ,3,'y')
524
False
525
526
Note that since :trac:`7797` there is a different
527
implementation of free algebras. Two corresponding free
528
algebras in different implementations are not equal, but there
529
is a coercion::
530
531
532
"""
533
if not isinstance(other, FreeAlgebra_generic):
534
return -1
535
c = cmp(self.base_ring(), other.base_ring())
536
if c: return c
537
c = cmp(self.__ngens, other.ngens())
538
if c: return c
539
c = cmp(self.variable_names(), other.variable_names())
540
if c: return c
541
return 0
542
543
def _repr_(self):
544
"""
545
Text representation of this free algebra.
546
547
EXAMPLES::
548
549
sage: F = FreeAlgebra(QQ,3,'x')
550
sage: F # indirect doctest
551
Free Algebra on 3 generators (x0, x1, x2) over Rational Field
552
sage: F.rename('QQ<<x0,x1,x2>>')
553
sage: F #indirect doctest
554
QQ<<x0,x1,x2>>
555
sage: FreeAlgebra(ZZ,1,['a'])
556
Free Algebra on 1 generators (a,) over Integer Ring
557
"""
558
return "Free Algebra on %s generators %s over %s"%(
559
self.__ngens, self.gens(), self.base_ring())
560
561
def _element_constructor_(self, x):
562
"""
563
Convert ``x`` into ``self``.
564
565
EXAMPLES::
566
567
sage: R.<x,y> = FreeAlgebra(QQ,2)
568
sage: R(3) # indirect doctest
569
3
570
571
TESTS::
572
573
sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
574
sage: L.<x,y,z> = FreeAlgebra(ZZ,3,implementation='letterplace')
575
sage: F(x) # indirect doctest
576
x
577
sage: F.1*L.2
578
y*z
579
sage: (F.1*L.2).parent() is F
580
True
581
582
::
583
584
sage: K.<z> = GF(25)
585
sage: F.<a,b,c> = FreeAlgebra(K,3)
586
sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace')
587
sage: F.1+(z+1)*L.2
588
b + (z+1)*c
589
590
Check that :trac:`15169` is fixed::
591
592
sage: A.<x> = FreeAlgebra(CC)
593
sage: A(2)
594
2.00000000000000
595
"""
596
if isinstance(x, FreeAlgebraElement):
597
P = x.parent()
598
if P is self:
599
return x
600
if not (P is self.base_ring()):
601
return self.element_class(self, x)
602
elif hasattr(x,'letterplace_polynomial'):
603
P = x.parent()
604
if self.has_coerce_map_from(P): # letterplace versus generic
605
ngens = P.ngens()
606
M = self._basis_keys
607
def exp_to_monomial(T):
608
out = []
609
for i in xrange(len(T)):
610
if T[i]:
611
out.append((i%ngens,T[i]))
612
return M(out)
613
return self.element_class(self, dict([(exp_to_monomial(T),c) for T,c in x.letterplace_polynomial().dict().iteritems()]))
614
# ok, not a free algebra element (or should not be viewed as one).
615
if isinstance(x, basestring):
616
from sage.all import sage_eval
617
return sage_eval(x,locals=self.gens_dict())
618
R = self.base_ring()
619
# coercion from free monoid
620
if isinstance(x, FreeMonoidElement) and x.parent() is self._basis_keys:
621
return self.element_class(self,{x:R(1)})
622
# coercion from the PBW basis
623
if isinstance(x, PBWBasisOfFreeAlgebra.Element) \
624
and self.has_coerce_map_from(x.parent()._alg):
625
return self(x.parent().expansion(x))
626
# coercion via base ring
627
x = R(x)
628
if x == 0:
629
return self.element_class(self,{})
630
return self.element_class(self,{self._basis_keys.one():x})
631
632
def _coerce_impl(self, x):
633
"""
634
Canonical coercion of ``x`` into ``self``.
635
636
Here's what canonically coerces to ``self``:
637
638
- this free algebra
639
640
- a free algebra in letterplace implementation that has
641
the same generator names and whose base ring coerces
642
into ``self``'s base ring
643
644
- the underlying monoid
645
646
- the PBW basis of ``self``
647
648
- anything that coerces to the base ring of this free algebra
649
650
- any free algebra whose base ring coerces to the base ring of
651
this free algebra
652
653
EXAMPLES::
654
655
sage: F.<x,y,z> = FreeAlgebra(GF(7),3); F
656
Free Algebra on 3 generators (x, y, z) over Finite Field of size 7
657
658
Elements of the free algebra canonically coerce in.
659
660
::
661
662
sage: F._coerce_(x*y) # indirect doctest
663
x*y
664
665
Elements of the integers coerce in, since there is a coerce map
666
from ZZ to GF(7).
667
668
::
669
670
sage: F._coerce_(1) # indirect doctest
671
1
672
673
There is no coerce map from QQ to GF(7).
674
675
::
676
677
sage: F._coerce_(2/3)
678
Traceback (most recent call last):
679
...
680
TypeError: no canonical coercion from Rational Field to Free Algebra
681
on 3 generators (x, y, z) over Finite Field of size 7
682
683
Elements of the base ring coerce in.
684
685
::
686
687
sage: F._coerce_(GF(7)(5))
688
5
689
690
Elements of the corresponding monoid (of monomials) coerce in::
691
692
sage: M = F.monoid(); m = M.0*M.1^2; m
693
x*y^2
694
sage: F._coerce_(m)
695
x*y^2
696
697
Elements of the PBW basis::
698
699
sage: PBW = F.pbw_basis()
700
sage: px,py,pz = PBW.gens()
701
sage: F(pz*px*py)
702
z*x*y
703
704
The free algebra over ZZ on x,y,z coerces in, since ZZ coerces to
705
GF(7)::
706
707
sage: G = FreeAlgebra(ZZ,3,'x,y,z')
708
sage: F._coerce_(G.0^3 * G.1)
709
x^3*y
710
711
However, GF(7) doesn't coerce to ZZ, so the free algebra over GF(7)
712
doesn't coerce to the one over ZZ::
713
714
sage: G._coerce_(x^3*y)
715
Traceback (most recent call last):
716
...
717
TypeError: no canonical coercion from Free Algebra on 3 generators
718
(x, y, z) over Finite Field of size 7 to Free Algebra on 3
719
generators (x, y, z) over Integer Ring
720
721
TESTS::
722
723
sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
724
sage: L.<x,y,z> = FreeAlgebra(GF(5),3,implementation='letterplace')
725
sage: F(x)
726
x
727
sage: F.1*L.2 # indirect doctest
728
y*z
729
730
"""
731
try:
732
R = x.parent()
733
734
# monoid
735
if R is self._basis_keys:
736
return self(x)
737
738
# polynomial rings in the same variable over any base that coerces in:
739
if is_FreeAlgebra(R):
740
if R.variable_names() == self.variable_names():
741
if self.has_coerce_map_from(R.base_ring()):
742
return self(x)
743
else:
744
raise TypeError("no natural map between bases of free algebras")
745
746
if isinstance(R, PBWBasisOfFreeAlgebra) and self.has_coerce_map_from(R._alg):
747
return self(R.expansion(x))
748
749
except AttributeError:
750
pass
751
752
# any ring that coerces to the base ring of this free algebra.
753
return self._coerce_try(x, [self.base_ring()])
754
755
def _coerce_map_from_(self, R):
756
"""
757
Return ``True`` if there is a coercion from ``R`` into ``self`` and
758
``False`` otherwise. The things that coerce into ``self`` are:
759
760
- Anything with a coercion into ``self.monoid()``.
761
762
- Free Algebras in the same variables over a base with a coercion
763
map into ``self.base_ring()``.
764
765
- The PBW basis of ``self``.
766
767
- Anything with a coercion into ``self.base_ring()``.
768
769
TESTS::
770
771
sage: F = FreeAlgebra(ZZ, 3, 'x,y,z')
772
sage: G = FreeAlgebra(QQ, 3, 'x,y,z')
773
sage: H = FreeAlgebra(ZZ, 1, 'y')
774
sage: F._coerce_map_from_(G)
775
False
776
sage: G._coerce_map_from_(F)
777
True
778
sage: F._coerce_map_from_(H)
779
False
780
sage: F._coerce_map_from_(QQ)
781
False
782
sage: G._coerce_map_from_(QQ)
783
True
784
sage: F._coerce_map_from_(G.monoid())
785
True
786
sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z'))
787
False
788
sage: K.<z> = GF(25)
789
sage: F.<a,b,c> = FreeAlgebra(K,3)
790
sage: L.<a,b,c> = FreeAlgebra(K,3, implementation='letterplace')
791
sage: F.1+(z+1)*L.2 # indirect doctest
792
b + (z+1)*c
793
794
"""
795
if self._basis_keys.has_coerce_map_from(R):
796
return True
797
798
# free algebras in the same variable over any base that coerces in:
799
if is_FreeAlgebra(R):
800
if R.variable_names() == self.variable_names():
801
if self.base_ring().has_coerce_map_from(R.base_ring()):
802
return True
803
else:
804
return False
805
if isinstance(R, PBWBasisOfFreeAlgebra):
806
return self.has_coerce_map_from(R._alg)
807
808
return self.base_ring().has_coerce_map_from(R)
809
810
def gen(self,i):
811
"""
812
The i-th generator of the algebra.
813
814
EXAMPLES::
815
816
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
817
sage: F.gen(0)
818
x
819
"""
820
n = self.__ngens
821
if i < 0 or not i < n:
822
raise IndexError("Argument i (= %s) must be between 0 and %s."%(i, n-1))
823
R = self.base_ring()
824
F = self._basis_keys
825
return self.element_class(self,{F.gen(i):R(1)})
826
827
def quotient(self, mons, mats, names):
828
"""
829
Returns a quotient algebra.
830
831
The quotient algebra is defined via the action of a free algebra
832
A on a (finitely generated) free module. The input for the quotient
833
algebra is a list of monomials (in the underlying monoid for A)
834
which form a free basis for the module of A, and a list of
835
matrices, which give the action of the free generators of A on this
836
monomial basis.
837
838
EXAMPLE:
839
840
Here is the quaternion algebra defined in terms of three generators::
841
842
sage: n = 3
843
sage: A = FreeAlgebra(QQ,n,'i')
844
sage: F = A.monoid()
845
sage: i, j, k = F.gens()
846
sage: mons = [ F(1), i, j, k ]
847
sage: M = MatrixSpace(QQ,4)
848
sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]), M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]), M([0,0,0,1, 0,0,-1,0, 0,1,0,0, -1,0,0,0]) ]
849
sage: H.<i,j,k> = A.quotient(mons, mats); H
850
Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 over Rational Field
851
"""
852
import free_algebra_quotient
853
return free_algebra_quotient.FreeAlgebraQuotient(self, mons, mats, names)
854
855
quo = quotient
856
857
def ngens(self):
858
"""
859
The number of generators of the algebra.
860
861
EXAMPLES::
862
863
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
864
sage: F.ngens()
865
3
866
"""
867
return self.__ngens
868
869
def monoid(self):
870
"""
871
The free monoid of generators of the algebra.
872
873
EXAMPLES::
874
875
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
876
sage: F.monoid()
877
Free monoid on 3 generators (x, y, z)
878
"""
879
return self._basis_keys
880
881
def g_algebra(self, relations, names=None, order='degrevlex', check = True):
882
"""
883
The G-Algebra derived from this algebra by relations.
884
By default is assumed, that two variables commute.
885
886
TODO:
887
888
- Coercion doesn't work yet, there is some cheating about assumptions
889
- The optional argument ``check`` controls checking the degeneracy
890
conditions. Furthermore, the default values interfere with
891
non-degeneracy conditions.
892
893
EXAMPLES::
894
895
sage: A.<x,y,z>=FreeAlgebra(QQ,3)
896
sage: G=A.g_algebra({y*x:-x*y})
897
sage: (x,y,z)=G.gens()
898
sage: x*y
899
x*y
900
sage: y*x
901
-x*y
902
sage: z*x
903
x*z
904
sage: (x,y,z)=A.gens()
905
sage: G=A.g_algebra({y*x:-x*y+1})
906
sage: (x,y,z)=G.gens()
907
sage: y*x
908
-x*y + 1
909
sage: (x,y,z)=A.gens()
910
sage: G=A.g_algebra({y*x:-x*y+z})
911
sage: (x,y,z)=G.gens()
912
sage: y*x
913
-x*y + z
914
"""
915
from sage.matrix.constructor import Matrix
916
917
base_ring=self.base_ring()
918
n=self.ngens()
919
cmat=Matrix(base_ring,n)
920
dmat=Matrix(self,n)
921
for i in xrange(n):
922
for j in xrange(i+1,n):
923
cmat[i,j]=1
924
for (to_commute,commuted) in relations.iteritems():
925
#This is dirty, coercion is broken
926
assert isinstance(to_commute,FreeAlgebraElement), to_commute.__class__
927
assert isinstance(commuted,FreeAlgebraElement), commuted
928
((v1,e1),(v2,e2))=list(list(to_commute)[0][1])
929
assert e1==1
930
assert e2==1
931
assert v1>v2
932
c_coef=None
933
d_poly=None
934
for (c,m) in commuted:
935
if list(m)==[(v2,1),(v1,1)]:
936
c_coef=c
937
#buggy coercion workaround
938
d_poly=commuted-self(c)*self(m)
939
break
940
assert not c_coef is None,list(m)
941
v2_ind = self.gens().index(v2)
942
v1_ind = self.gens().index(v1)
943
cmat[v2_ind,v1_ind]=c_coef
944
if d_poly:
945
dmat[v2_ind,v1_ind]=d_poly
946
from sage.rings.polynomial.plural import g_Algebra
947
return g_Algebra(base_ring, cmat, dmat, names = names or self.variable_names(),
948
order=order, check=check)
949
950
def poincare_birkhoff_witt_basis(self):
951
"""
952
Return the Poincare-Birkhoff-Witt (PBW) basis of ``self``.
953
954
EXAMPLES::
955
956
sage: F.<x,y> = FreeAlgebra(QQ, 2)
957
sage: F.poincare_birkhoff_witt_basis()
958
The Poincare-Birkhoff-Witt basis of Free Algebra on 2 generators (x, y) over Rational Field
959
"""
960
return PBWBasisOfFreeAlgebra(self)
961
962
pbw_basis = poincare_birkhoff_witt_basis
963
964
def pbw_element(self, elt):
965
"""
966
Return the element ``elt`` in the Poincare-Birkhoff-Witt basis.
967
968
EXAMPLES::
969
970
sage: F.<x,y> = FreeAlgebra(QQ, 2)
971
sage: F.pbw_element(x*y - y*x + 2)
972
2*PBW[1] + PBW[x*y]
973
sage: F.pbw_element(F.one())
974
PBW[1]
975
sage: F.pbw_element(x*y*x + x^3*y)
976
PBW[x*y]*PBW[x] + PBW[y]*PBW[x]^2 + PBW[x^3*y] + PBW[x^2*y]*PBW[x]
977
+ PBW[x*y]*PBW[x]^2 + PBW[y]*PBW[x]^3
978
"""
979
PBW = self.pbw_basis()
980
if elt == self.zero():
981
return PBW.zero()
982
983
l = {}
984
while elt: # != 0
985
lst = list(elt)
986
support = [i[1].to_word() for i in lst]
987
min_elt = support[0]
988
for word in support[1:len(support)-1]:
989
if min_elt.lex_less(word):
990
min_elt = word
991
coeff = lst[support.index(min_elt)][0]
992
min_elt = min_elt.to_monoid_element()
993
l[min_elt] = l.get(min_elt, 0) + coeff
994
elt = elt - coeff * self.lie_polynomial(min_elt)
995
return PBW.sum_of_terms([(k, v) for k,v in l.items() if v != 0], distinct=True)
996
997
def lie_polynomial(self, w):
998
"""
999
Return the Lie polynomial associated to the Lyndon word ``w``. If
1000
``w`` is not Lyndon, then return the product of Lie polynomials of the
1001
Lyndon factorization of ``w``.
1002
1003
INPUT:
1004
1005
- ``w``-- a word or an element of the free monoid
1006
1007
EXAMPLES::
1008
1009
sage: F = FreeAlgebra(QQ, 3, 'x,y,z')
1010
sage: M.<x,y,z> = FreeMonoid(3)
1011
sage: F.lie_polynomial(x*y)
1012
x*y - y*x
1013
sage: F.lie_polynomial(y*x)
1014
y*x
1015
sage: F.lie_polynomial(x^2*y*x)
1016
x^2*y*x - x*y*x^2
1017
sage: F.lie_polynomial(y*z*x*z*x*z)
1018
y*z*x*z*x*z - y*z*x*z^2*x - y*z^2*x^2*z + y*z^2*x*z*x
1019
- z*y*x*z*x*z + z*y*x*z^2*x + z*y*z*x^2*z - z*y*z*x*z*x
1020
1021
TESTS:
1022
1023
We test some corner cases and alternative inputs::
1024
1025
sage: F.lie_polynomial(Word('xy'))
1026
x*y - y*x
1027
sage: F.lie_polynomial('xy')
1028
x*y - y*x
1029
sage: F.lie_polynomial(M.one())
1030
1
1031
sage: F.lie_polynomial(Word([]))
1032
1
1033
sage: F.lie_polynomial('')
1034
1
1035
"""
1036
if not w:
1037
return self.one()
1038
M = self._basis_keys
1039
1040
if len(w) == 1:
1041
return self(M(w))
1042
1043
ret = self.one()
1044
# We have to be careful about order here.
1045
# Since the Lyndon factors appear from left to right
1046
# we must multiply from left to right as well.
1047
for factor in Word(w).lyndon_factorization():
1048
if len(factor) == 1:
1049
ret = ret * self(M(factor))
1050
continue
1051
x,y = factor.standard_factorization()
1052
x = M(x)
1053
y = M(y)
1054
ret = ret * (self(x * y) - self(y * x))
1055
return ret
1056
1057
from sage.misc.cache import Cache
1058
cache = Cache(FreeAlgebra_generic)
1059
1060
class PBWBasisOfFreeAlgebra(CombinatorialFreeModule):
1061
"""
1062
The Poincare-Birkhoff-Witt basis of the free algebra.
1063
1064
EXAMPLES::
1065
1066
sage: F.<x,y> = FreeAlgebra(QQ, 2)
1067
sage: PBW = F.pbw_basis()
1068
sage: px, py = PBW.gens()
1069
sage: px * py
1070
PBW[x*y] + PBW[y]*PBW[x]
1071
sage: py * px
1072
PBW[y]*PBW[x]
1073
sage: px * py^3 * px - 2*px * py
1074
-2*PBW[x*y] - 2*PBW[y]*PBW[x] + PBW[x*y^3]*PBW[x] + PBW[y]*PBW[x*y^2]*PBW[x]
1075
+ PBW[y]^2*PBW[x*y]*PBW[x] + PBW[y]^3*PBW[x]^2
1076
1077
We can convert between the two bases::
1078
1079
sage: p = PBW(x*y - y*x + 2); p
1080
2*PBW[1] + PBW[x*y]
1081
sage: F(p)
1082
2 + x*y - y*x
1083
sage: f = F.pbw_element(x*y*x + x^3*y + x + 3)
1084
sage: F(PBW(f)) == f
1085
True
1086
sage: p = px*py + py^4*px^2
1087
sage: F(p)
1088
x*y + y^4*x^2
1089
sage: PBW(F(p)) == p
1090
True
1091
1092
Note that multiplication in the PBW basis agrees with multiplication
1093
as monomials::
1094
1095
sage: F(px * py^3 * px - 2*px * py) == x*y^3*x - 2*x*y
1096
True
1097
1098
TESTS:
1099
1100
Check that going between the two bases is the identity::
1101
1102
sage: F = FreeAlgebra(QQ, 2, 'x,y')
1103
sage: PBW = F.pbw_basis()
1104
sage: M = F.monoid()
1105
sage: L = [j.to_monoid_element() for i in range(6) for j in Words('xy', i)]
1106
sage: all(PBW(F(PBW(m))) == PBW(m) for m in L)
1107
True
1108
sage: all(F(PBW(F(m))) == F(m) for m in L)
1109
True
1110
"""
1111
@staticmethod
1112
def __classcall_private__(cls, R, n=None, names=None):
1113
"""
1114
Normalize input to ensure a unique representation.
1115
1116
EXAMPLES::
1117
1118
sage: from sage.algebras.free_algebra import PBWBasisOfFreeAlgebra
1119
sage: PBW1 = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1120
sage: PBW2.<x,y> = PBWBasisOfFreeAlgebra(QQ)
1121
sage: PBW3 = PBWBasisOfFreeAlgebra(QQ, 2, ['x','y'])
1122
sage: PBW1 is PBW2 and PBW2 is PBW3
1123
True
1124
"""
1125
if n is None and names is None:
1126
if not isinstance(R, FreeAlgebra_generic):
1127
raise ValueError("{} is not a free algebra".format(R))
1128
alg = R
1129
else:
1130
if n is None:
1131
n = len(names)
1132
alg = FreeAlgebra(R, n, names)
1133
return super(PBWBasisOfFreeAlgebra, cls).__classcall__(cls, alg)
1134
1135
def __init__(self, alg):
1136
"""
1137
Initialize ``self``.
1138
1139
EXAMPLES::
1140
1141
sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1142
sage: TestSuite(PBW).run()
1143
"""
1144
R = alg.base_ring()
1145
self._alg = alg
1146
category = AlgebrasWithBasis(R)
1147
CombinatorialFreeModule.__init__(self, R, alg.monoid(), prefix='PBW',
1148
category=category)
1149
self._assign_names(alg.variable_names())
1150
1151
def _repr_(self):
1152
"""
1153
Return a string representation of ``self``.
1154
1155
EXAMPLES::
1156
1157
sage: FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1158
The Poincare-Birkhoff-Witt basis of Free Algebra on 2 generators (x, y) over Rational Field
1159
"""
1160
return "The Poincare-Birkhoff-Witt basis of %s"%(self._alg)
1161
1162
def _repr_term(self, w):
1163
"""
1164
Return a representation of term indexed by ``w``.
1165
1166
EXAMPLES::
1167
1168
sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1169
sage: x,y = PBW.gens()
1170
sage: x*y # indirect doctest
1171
PBW[x*y] + PBW[y]*PBW[x]
1172
sage: y*x
1173
PBW[y]*PBW[x]
1174
sage: x^3
1175
PBW[x]^3
1176
sage: PBW.one()
1177
PBW[1]
1178
sage: 3*PBW.one()
1179
3*PBW[1]
1180
"""
1181
if len(w) == 0:
1182
return super(PBWBasisOfFreeAlgebra, self)._repr_term(w)
1183
ret = ''
1184
p = 1
1185
cur = None
1186
for x in w.to_word().lyndon_factorization():
1187
if x == cur:
1188
p += 1
1189
else:
1190
if len(ret) != 0:
1191
if p != 1:
1192
ret += "^{}".format(p)
1193
ret += "*"
1194
ret += super(PBWBasisOfFreeAlgebra, self)._repr_term(x.to_monoid_element())
1195
cur = x
1196
p = 1
1197
if p != 1:
1198
ret += "^{}".format(p)
1199
return ret
1200
1201
def _element_constructor_(self, x):
1202
"""
1203
Convert ``x`` into ``self``.
1204
1205
EXAMPLES::
1206
1207
sage: F.<x,y> = FreeAlgebra(QQ, 2)
1208
sage: R = F.pbw_basis()
1209
sage: R(3)
1210
3*PBW[1]
1211
sage: R(x*y)
1212
PBW[x*y] + PBW[y]*PBW[x]
1213
"""
1214
if isinstance(x, FreeAlgebraElement):
1215
return self._alg.pbw_element(self._alg(x))
1216
return CombinatorialFreeModule._element_constructor_(self, x)
1217
1218
def _coerce_map_from_(self, R):
1219
"""
1220
Return ``True`` if there is a coercion from ``R`` into ``self`` and
1221
``False`` otherwise. The things that coerce into ``self`` are:
1222
1223
- Anything that coerces into the associated free algebra of ``self``
1224
1225
TESTS::
1226
1227
sage: F = FreeAlgebra(ZZ, 3, 'x,y,z').pbw_basis()
1228
sage: G = FreeAlgebra(QQ, 3, 'x,y,z').pbw_basis()
1229
sage: H = FreeAlgebra(ZZ, 1, 'y').pbw_basis()
1230
sage: F._coerce_map_from_(G)
1231
False
1232
sage: G._coerce_map_from_(F)
1233
True
1234
sage: F._coerce_map_from_(H)
1235
False
1236
sage: F._coerce_map_from_(QQ)
1237
False
1238
sage: G._coerce_map_from_(QQ)
1239
True
1240
sage: F._coerce_map_from_(G._alg.monoid())
1241
True
1242
sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z'))
1243
False
1244
sage: F.has_coerce_map_from(FreeAlgebra(ZZ, 3, 'x,y,z'))
1245
True
1246
"""
1247
return self._alg.has_coerce_map_from(R)
1248
1249
def one_basis(self):
1250
"""
1251
Return the index of the basis element for `1`.
1252
1253
EXAMPLES::
1254
1255
sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1256
sage: PBW.one_basis()
1257
1
1258
sage: PBW.one_basis().parent()
1259
Free monoid on 2 generators (x, y)
1260
"""
1261
return self._basis_keys.one()
1262
1263
def algebra_generators(self):
1264
"""
1265
Return the generators of ``self`` as an algebra.
1266
1267
EXAMPLES::
1268
1269
sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1270
sage: gens = PBW.algebra_generators(); gens
1271
(PBW[x], PBW[y])
1272
sage: all(g.parent() is PBW for g in gens)
1273
True
1274
"""
1275
return tuple(self.monomial(x) for x in self._basis_keys.gens())
1276
1277
gens = algebra_generators
1278
1279
def gen(self, i):
1280
"""
1281
Return the ``i``-th generator of ``self``.
1282
1283
EXAMPLES::
1284
1285
sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1286
sage: PBW.gen(0)
1287
PBW[x]
1288
sage: PBW.gen(1)
1289
PBW[y]
1290
"""
1291
return self.algebra_generators()[i]
1292
1293
def free_algebra(self):
1294
"""
1295
Return the associated free algebra of ``self``.
1296
1297
EXAMPLES::
1298
1299
sage: PBW = FreeAlgebra(QQ, 2, 'x,y').pbw_basis()
1300
sage: PBW.free_algebra()
1301
Free Algebra on 2 generators (x, y) over Rational Field
1302
"""
1303
return self._alg
1304
1305
def product(self, u, v):
1306
"""
1307
Return the product of two elements ``u`` and ``v``.
1308
1309
EXAMPLES::
1310
1311
sage: F = FreeAlgebra(QQ, 2, 'x,y')
1312
sage: PBW = F.pbw_basis()
1313
sage: x, y = PBW.gens()
1314
sage: PBW.product(x, y)
1315
PBW[x*y] + PBW[y]*PBW[x]
1316
sage: PBW.product(y, x)
1317
PBW[y]*PBW[x]
1318
sage: PBW.product(y^2*x, x*y*x)
1319
PBW[y]^2*PBW[x^2*y]*PBW[x] + PBW[y]^2*PBW[x*y]*PBW[x]^2 + PBW[y]^3*PBW[x]^3
1320
1321
TESTS:
1322
1323
Check that multiplication agrees with the multiplication in the
1324
free algebra::
1325
1326
sage: F = FreeAlgebra(QQ, 2, 'x,y')
1327
sage: PBW = F.pbw_basis()
1328
sage: x, y = PBW.gens()
1329
sage: F(x*y)
1330
x*y
1331
sage: F(x*y*x)
1332
x*y*x
1333
sage: PBW(F(x)*F(y)*F(x)) == x*y*x
1334
True
1335
"""
1336
return self(self.expansion(u) * self.expansion(v))
1337
1338
def expansion(self, t):
1339
"""
1340
Return the expansion of the element ``t`` of the Poincare-Birkhoff-Witt
1341
basis in the monomials of the free algebra.
1342
1343
EXAMPLES::
1344
1345
sage: F = FreeAlgebra(QQ, 2, 'x,y')
1346
sage: PBW = F.pbw_basis()
1347
sage: x,y = F.monoid().gens()
1348
sage: PBW.expansion(PBW(x*y))
1349
x*y - y*x
1350
sage: PBW.expansion(PBW.one())
1351
1
1352
sage: PBW.expansion(PBW(x*y*x) + 2*PBW(x) + 3)
1353
3 + 2*x + x*y*x - y*x^2
1354
1355
TESTS:
1356
1357
Check that we have the correct parent::
1358
1359
sage: PBW.expansion(PBW(x*y)).parent() is F
1360
True
1361
sage: PBW.expansion(PBW.one()).parent() is F
1362
True
1363
"""
1364
return sum([i[1] * self._alg.lie_polynomial(i[0]) for i in list(t)],
1365
self._alg.zero())
1366
1367
class Element(CombinatorialFreeModuleElement):
1368
def expand(self):
1369
"""
1370
Expand ``self`` in the monomials of the free algebra.
1371
1372
EXAMPLES::
1373
1374
sage: F = FreeAlgebra(QQ, 2, 'x,y')
1375
sage: PBW = F.pbw_basis()
1376
sage: x,y = F.monoid().gens()
1377
sage: f = PBW(x^2*y) + PBW(x) + PBW(y^4*x)
1378
sage: f.expand()
1379
x + x^2*y - x*y*x + y^4*x
1380
"""
1381
return self.parent().expansion(self)
1382
1383
1384