Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/algebras/free_algebra.py
4102 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
13
EXAMPLES::
14
15
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
16
sage: F.base_ring()
17
Integer Ring
18
sage: G = FreeAlgebra(F, 2, 'm,n'); G
19
Free Algebra on 2 generators (m, n) over Free Algebra on 3 generators (x, y, z) over Integer Ring
20
sage: G.base_ring()
21
Free Algebra on 3 generators (x, y, z) over Integer Ring
22
23
TESTS::
24
25
sage: F = FreeAlgebra(GF(5),3,'x')
26
sage: TestSuite(F).run()
27
28
::
29
30
sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
31
sage: TestSuite(F).run()
32
33
::
34
35
sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y'])
36
sage: TestSuite(F).run()
37
38
::
39
40
sage: F = FreeAlgebra(GF(5),3, 'abc')
41
sage: TestSuite(F).run()
42
43
::
44
45
sage: F = FreeAlgebra(FreeAlgebra(ZZ,1,'a'), 2, 'x')
46
sage: TestSuite(F).run()
47
48
"""
49
50
#*****************************************************************************
51
# Copyright (C) 2005 David Kohel <[email protected]>
52
# Copyright (C) 2005,2006 William Stein <[email protected]>
53
# Copyright (C) 2011 Simon King <[email protected]>
54
#
55
# Distributed under the terms of the GNU General Public License (GPL)
56
# http://www.gnu.org/licenses/
57
#*****************************************************************************
58
59
from sage.rings.ring import Ring
60
61
from sage.monoids.free_monoid import FreeMonoid
62
from sage.monoids.free_monoid_element import FreeMonoidElement
63
64
from sage.algebras.algebra import Algebra
65
from sage.algebras.free_algebra_element import FreeAlgebraElement
66
67
import sage.structure.parent_gens
68
69
def FreeAlgebra(R, n, names):
70
"""
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
84
EXAMPLES::
85
86
sage: FreeAlgebra(GF(5),3,'x')
87
Free Algebra on 3 generators (x0, x1, x2) over Finite Field of size 5
88
sage: F.<x,y,z> = FreeAlgebra(GF(5),3)
89
sage: (x+y+z)^2
90
x^2 + x*y + x*z + y*x + y^2 + y*z + z*x + z*y + z^2
91
sage: FreeAlgebra(GF(5),3, 'xx, zba, Y')
92
Free Algebra on 3 generators (xx, zba, Y) over Finite Field of size 5
93
sage: FreeAlgebra(GF(5),3, 'abc')
94
Free Algebra on 3 generators (a, b, c) over Finite Field of size 5
95
sage: FreeAlgebra(GF(5),1, 'z')
96
Free Algebra on 1 generators (z,) over Finite Field of size 5
97
sage: FreeAlgebra(GF(5),1, ['alpha'])
98
Free Algebra on 1 generators (alpha,) over Finite Field of size 5
99
sage: FreeAlgebra(FreeAlgebra(ZZ,1,'a'), 2, 'x')
100
Free Algebra on 2 generators (x0, x1) over Free Algebra on 1 generators (a,) over Integer Ring
101
102
Free algebras are globally unique::
103
104
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
105
sage: G = FreeAlgebra(ZZ,3,'x,y,z')
106
sage: F is G
107
True
108
109
Free algebras commute with their base ring.
110
::
111
112
sage: K.<a,b> = FreeAlgebra(QQ,2)
113
sage: K.is_commutative()
114
False
115
sage: L.<c> = FreeAlgebra(K,1)
116
sage: L.is_commutative()
117
False
118
sage: s = a*b^2 * c^3; s
119
a*b^2*c^3
120
sage: parent(s)
121
Free Algebra on 1 generators (c,) over Free Algebra on 2 generators (a, b) over Rational Field
122
sage: c^3 * a * b^2
123
a*b^2*c^3
124
"""
125
names = sage.structure.parent_gens.normalize_names(n, names)
126
return cache(R, n, names)
127
128
def is_FreeAlgebra(x):
129
"""
130
Return True if x is a free algebra; otherwise, return False.
131
132
EXAMPLES::
133
134
sage: from sage.algebras.free_algebra import is_FreeAlgebra
135
sage: is_FreeAlgebra(5)
136
False
137
sage: is_FreeAlgebra(ZZ)
138
False
139
sage: is_FreeAlgebra(FreeAlgebra(ZZ,100,'x'))
140
True
141
"""
142
return isinstance(x, FreeAlgebra_generic)
143
144
145
class FreeAlgebra_generic(Algebra):
146
"""
147
The free algebra on `n` generators over a base ring.
148
149
EXAMPLES::
150
151
sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F
152
Free Algebra on 3 generators (x, y, z) over Rational Field
153
sage: mul(F.gens())
154
x*y*z
155
sage: mul([ F.gen(i%3) for i in range(12) ])
156
x*y*z*x*y*z*x*y*z*x*y*z
157
sage: mul([ F.gen(i%3) for i in range(12) ]) + mul([ F.gen(i%2) for i in range(12) ])
158
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
sage: (2 + x*z + x^2)^2 + (x - y)^2
160
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
161
"""
162
Element = FreeAlgebraElement
163
def __init__(self, R, n, names):
164
"""
165
The free algebra on `n` generators over a base ring.
166
167
INPUT:
168
169
- ``R`` - ring
170
- ``n`` - an integer
171
- ``names`` - generator names
172
173
EXAMPLES::
174
175
sage: F.<x,y,z> = FreeAlgebra(QQ, 3); F # indirect doctet
176
Free Algebra on 3 generators (x, y, z) over Rational Field
177
"""
178
if not isinstance(R, Ring):
179
raise TypeError("Argument R must be a ring.")
180
self.__monoid = FreeMonoid(n, names=names)
181
self.__ngens = n
182
#sage.structure.parent_gens.ParentWithGens.__init__(self, R, names)
183
Algebra.__init__(self, R,names=names)
184
185
def is_field(self, proof = True):
186
"""
187
Return True if this Free Algebra is a field, which is only if the
188
base ring is a field and there are no generators
189
190
EXAMPLES::
191
192
sage: A=FreeAlgebra(QQ,0,'')
193
sage: A.is_field()
194
True
195
sage: A=FreeAlgebra(QQ,1,'x')
196
sage: A.is_field()
197
False
198
"""
199
if self.__ngens == 0:
200
return self.base_ring().is_field(proof)
201
return False
202
203
def is_commutative(self):
204
"""
205
Return True if this free algebra is commutative.
206
207
EXAMPLES::
208
209
sage: R.<x> = FreeAlgebra(QQ,1)
210
sage: R.is_commutative()
211
True
212
sage: R.<x,y> = FreeAlgebra(QQ,2)
213
sage: R.is_commutative()
214
False
215
"""
216
return self.__ngens <= 1 and self.base_ring().is_commutative()
217
218
def __cmp__(self, other):
219
"""
220
Two free algebras are considered the same if they have the same
221
base ring, number of generators and variable names.
222
223
EXAMPLES::
224
225
sage: F = FreeAlgebra(QQ,3,'x')
226
sage: F == FreeAlgebra(QQ,3,'x')
227
True
228
sage: F is FreeAlgebra(QQ,3,'x')
229
True
230
sage: F == FreeAlgebra(ZZ,3,'x')
231
False
232
sage: F == FreeAlgebra(QQ,4,'x')
233
False
234
sage: F == FreeAlgebra(QQ,3,'y')
235
False
236
"""
237
if not isinstance(other, FreeAlgebra_generic):
238
return -1
239
c = cmp(self.base_ring(), other.base_ring())
240
if c: return c
241
c = cmp(self.__ngens, other.__ngens)
242
if c: return c
243
c = cmp(self.variable_names(), other.variable_names())
244
if c: return c
245
return 0
246
247
def _repr_(self):
248
"""
249
Text representation of this free algebra.
250
251
EXAMPLES::
252
253
sage: F = FreeAlgebra(QQ,3,'x')
254
sage: print F # indirect doctest
255
Free Algebra on 3 generators (x0, x1, x2) over Rational Field
256
sage: F.rename('QQ<<x0,x1,x2>>')
257
sage: print F #indirect doctest
258
QQ<<x0,x1,x2>>
259
sage: FreeAlgebra(ZZ,1,['a'])
260
Free Algebra on 1 generators (a,) over Integer Ring
261
"""
262
return "Free Algebra on %s generators %s over %s"%(
263
self.__ngens, self.gens(), self.base_ring())
264
265
def _element_constructor_(self, x):
266
"""
267
Coerce x into self.
268
269
EXAMPLES::
270
271
sage: R.<x,y> = FreeAlgebra(QQ,2)
272
sage: R(3) # indirect doctest
273
3
274
"""
275
if isinstance(x, FreeAlgebraElement):
276
P = x.parent()
277
if P is self:
278
return x
279
if not (P is self.base_ring()):
280
return self.element_class(self, x)
281
# ok, not a free algebra element (or should not be viewed as one).
282
F = self.__monoid
283
R = self.base_ring()
284
# coercion from free monoid
285
if isinstance(x, FreeMonoidElement) and x.parent() is F:
286
return self.element_class(self,{x:R(1)})
287
# coercion via base ring
288
x = R(x)
289
if x == 0:
290
return self.element_class(self,{})
291
else:
292
return self.element_class(self,{F(1):x})
293
294
def _coerce_impl(self, x):
295
"""
296
Canonical coercion of x into self.
297
298
Here's what canonically coerces to self:
299
300
- this free algebra
301
302
- the underlying monoid
303
304
- anything that coerces to the base ring of this free algebra
305
306
- any free algebra whose base ring coerces to the base ring of
307
this free algebra
308
309
EXAMPLES::
310
311
sage: F.<x,y,z> = FreeAlgebra(GF(7),3); F
312
Free Algebra on 3 generators (x, y, z) over Finite Field of size 7
313
314
Elements of the free algebra canonically coerce in.
315
316
::
317
318
sage: F._coerce_(x*y) # indirect doctest
319
x*y
320
321
Elements of the integers coerce in, since there is a coerce map
322
from ZZ to GF(7).
323
324
::
325
326
sage: F._coerce_(1) # indirect doctest
327
1
328
329
There is no coerce map from QQ to GF(7).
330
331
::
332
333
sage: F._coerce_(2/3)
334
Traceback (most recent call last):
335
...
336
TypeError: no canonical coercion from Rational Field to Free Algebra
337
on 3 generators (x, y, z) over Finite Field of size 7
338
339
Elements of the base ring coerce in.
340
341
::
342
343
sage: F._coerce_(GF(7)(5))
344
5
345
346
Elements of the corresponding monoid (of monomials) coerce in::
347
348
sage: M = F.monoid(); m = M.0*M.1^2; m
349
x*y^2
350
sage: F._coerce_(m)
351
x*y^2
352
353
The free algebra over ZZ on x,y,z coerces in, since ZZ coerces to
354
GF(7)::
355
356
sage: G = FreeAlgebra(ZZ,3,'x,y,z')
357
sage: F._coerce_(G.0^3 * G.1)
358
x^3*y
359
360
However, GF(7) doesn't coerce to ZZ, so the free algebra over GF(7)
361
doesn't coerce to the one over ZZ::
362
363
sage: G._coerce_(x^3*y)
364
Traceback (most recent call last):
365
...
366
TypeError: no canonical coercion from Free Algebra on 3 generators
367
(x, y, z) over Finite Field of size 7 to Free Algebra on 3
368
generators (x, y, z) over Integer Ring
369
"""
370
try:
371
R = x.parent()
372
373
# monoid
374
if R is self.__monoid:
375
return self(x)
376
377
# polynomial rings in the same variable over any base that coerces in:
378
if is_FreeAlgebra(R):
379
if R.variable_names() == self.variable_names():
380
if self.has_coerce_map_from(R.base_ring()):
381
return self(x)
382
else:
383
raise TypeError("no natural map between bases of free algebras")
384
385
except AttributeError:
386
pass
387
388
# any ring that coerces to the base ring of this free algebra.
389
return self._coerce_try(x, [self.base_ring()])
390
391
def _coerce_map_from_(self, R):
392
"""
393
Returns True if there is a coercion from R into self and false
394
otherwise. The things that coerce into self are:
395
396
- Anything with a coercion into self.monoid()
397
398
- Free Algebras in the same variables over a base with a coercion
399
map into self.base_ring()
400
401
- Anything with a coercion into self.base_ring()
402
403
TESTS::
404
405
sage: F = FreeAlgebra(ZZ, 3, 'x,y,z')
406
sage: G = FreeAlgebra(QQ, 3, 'x,y,z')
407
sage: H = FreeAlgebra(ZZ, 1, 'y')
408
sage: F._coerce_map_from_(G)
409
False
410
sage: G._coerce_map_from_(F)
411
True
412
sage: F._coerce_map_from_(H)
413
False
414
sage: F._coerce_map_from_(QQ)
415
False
416
sage: G._coerce_map_from_(QQ)
417
True
418
sage: F._coerce_map_from_(G.monoid())
419
True
420
sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z'))
421
False
422
"""
423
if self.__monoid.has_coerce_map_from(R):
424
return True
425
426
# free algebras in the same variable over any base that coerces in:
427
if is_FreeAlgebra(R):
428
if R.variable_names() == self.variable_names():
429
if self.base_ring().has_coerce_map_from(R.base_ring()):
430
return True
431
else:
432
return False
433
434
return self.base_ring().has_coerce_map_from(R)
435
436
def gen(self,i):
437
"""
438
The i-th generator of the algebra.
439
440
EXAMPLES::
441
442
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
443
sage: F.gen(0)
444
x
445
"""
446
n = self.__ngens
447
if i < 0 or not i < n:
448
raise IndexError("Argument i (= %s) must be between 0 and %s."%(i, n-1))
449
R = self.base_ring()
450
F = self.__monoid
451
return self.element_class(self,{F.gen(i):R(1)})
452
453
def quotient(self, mons, mats, names):
454
"""
455
Returns a quotient algebra.
456
457
The quotient algebra is defined via the action of a free algebra
458
A on a (finitely generated) free module. The input for the quotient
459
algebra is a list of monomials (in the underlying monoid for A)
460
which form a free basis for the module of A, and a list of
461
matrices, which give the action of the free generators of A on this
462
monomial basis.
463
464
EXAMPLE:
465
466
Here is the quaternion algebra defined in terms of three generators::
467
468
sage: n = 3
469
sage: A = FreeAlgebra(QQ,n,'i')
470
sage: F = A.monoid()
471
sage: i, j, k = F.gens()
472
sage: mons = [ F(1), i, j, k ]
473
sage: M = MatrixSpace(QQ,4)
474
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]) ]
475
sage: H.<i,j,k> = A.quotient(mons, mats); H
476
Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 over Rational Field
477
"""
478
import free_algebra_quotient
479
return free_algebra_quotient.FreeAlgebraQuotient(self, mons, mats, names)
480
quo = quotient
481
482
def ngens(self):
483
"""
484
The number of generators of the algebra.
485
486
EXAMPLES::
487
488
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
489
sage: F.ngens()
490
3
491
"""
492
return self.__ngens
493
494
def monoid(self):
495
"""
496
The free monoid of generators of the algebra.
497
498
EXAMPLES::
499
500
sage: F = FreeAlgebra(ZZ,3,'x,y,z')
501
sage: F.monoid()
502
Free monoid on 3 generators (x, y, z)
503
"""
504
return self.__monoid
505
506
def g_algebra(self, relations, names=None, order='degrevlex', check = True):
507
"""
508
The G-Algebra derived from this algebra by relations.
509
By default is assumed, that two variables commute.
510
511
TODO:
512
513
- Coercion doesn't work yet, there is some cheating about assumptions
514
- The optional argument ``check`` controls checking the degeneracy
515
conditions. Furthermore, the default values interfere with
516
non-degeneracy conditions.
517
518
EXAMPLES::
519
520
sage: A.<x,y,z>=FreeAlgebra(QQ,3)
521
sage: G=A.g_algebra({y*x:-x*y})
522
sage: (x,y,z)=G.gens()
523
sage: x*y
524
x*y
525
sage: y*x
526
-x*y
527
sage: z*x
528
x*z
529
sage: (x,y,z)=A.gens()
530
sage: G=A.g_algebra({y*x:-x*y+1})
531
sage: (x,y,z)=G.gens()
532
sage: y*x
533
-x*y + 1
534
sage: (x,y,z)=A.gens()
535
sage: G=A.g_algebra({y*x:-x*y+z})
536
sage: (x,y,z)=G.gens()
537
sage: y*x
538
-x*y + z
539
"""
540
from sage.matrix.constructor import Matrix
541
542
base_ring=self.base_ring()
543
n=self.ngens()
544
cmat=Matrix(base_ring,n)
545
dmat=Matrix(self,n)
546
for i in xrange(n):
547
for j in xrange(i+1,n):
548
cmat[i,j]=1
549
for (to_commute,commuted) in relations.iteritems():
550
#This is dirty, coercion is broken
551
assert isinstance(to_commute,FreeAlgebraElement), to_commute.__class__
552
assert isinstance(commuted,FreeAlgebraElement), commuted
553
((v1,e1),(v2,e2))=list(list(to_commute)[0][1])
554
assert e1==1
555
assert e2==1
556
assert v1>v2
557
c_coef=None
558
d_poly=None
559
for (c,m) in commuted:
560
if list(m)==[(v2,1),(v1,1)]:
561
c_coef=c
562
#buggy coercion workaround
563
d_poly=commuted-self(c)*self(m)
564
break
565
assert not c_coef is None,list(m)
566
v2_ind = self.gens().index(v2)
567
v1_ind = self.gens().index(v1)
568
cmat[v2_ind,v1_ind]=c_coef
569
if d_poly:
570
dmat[v2_ind,v1_ind]=d_poly
571
from sage.rings.polynomial.plural import g_Algebra
572
return g_Algebra(base_ring, cmat, dmat, names = names or self.variable_names(),
573
order=order, check=check)
574
575
from sage.misc.cache import Cache
576
cache = Cache(FreeAlgebra_generic)
577
578