Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/monoids/free_monoid_element.py
4069 views
1
"""
2
Monoid Elements
3
4
AUTHORS:
5
6
- David Kohel (2005-09-29)
7
8
Elements of free monoids are represented internally as lists of
9
pairs of integers.
10
"""
11
12
#*****************************************************************************
13
# Copyright (C) 2005 David Kohel <[email protected]>
14
#
15
# Distributed under the terms of the GNU General Public License (GPL)
16
#
17
# This code is distributed in the hope that it will be useful,
18
# but WITHOUT ANY WARRANTY; without even the implied warranty
19
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20
#
21
# See the GNU General Public License for more details; the full text
22
# is available at:
23
#
24
# http://www.gnu.org/licenses/
25
#*****************************************************************************
26
27
from sage.rings.integer import Integer
28
from sage.structure.element import MonoidElement
29
30
def is_FreeMonoidElement(x):
31
return isinstance(x, FreeMonoidElement)
32
33
class FreeMonoidElement(MonoidElement):
34
"""
35
Element of a free monoid.
36
37
EXAMPLES::
38
39
sage: a = FreeMonoid(5, 'a').gens()
40
sage: x = a[0]*a[1]*a[4]**3
41
sage: x**3
42
a0*a1*a4^3*a0*a1*a4^3*a0*a1*a4^3
43
sage: x**0
44
1
45
sage: x**(-1)
46
Traceback (most recent call last):
47
...
48
TypeError: bad operand type for unary ~: 'FreeMonoid_class_with_category.element_class'
49
"""
50
def __init__(self, F, x, check=True):
51
"""
52
Create the element `x` of the FreeMonoid `F`.
53
54
This should typically be called by a FreeMonoid.
55
"""
56
MonoidElement.__init__(self, F)
57
if isinstance(x, (int, long, Integer)):
58
if x == 1:
59
self._element_list = []
60
else:
61
raise TypeError, "Argument x (= %s) is of the wrong type."%x
62
elif isinstance(x, list):
63
if check:
64
x2 = []
65
for v in x:
66
if not isinstance(v, tuple) and len(v) == 2:
67
raise TypeError, "x (= %s) must be a list of 2-tuples or 1."%x
68
if not (isinstance(v[0], (int,long,Integer)) and \
69
isinstance(v[1], (int,long,Integer))):
70
raise TypeError, "x (= %s) must be a list of 2-tuples of integers or 1."%x
71
if len(x2) > 0 and v[0] == x2[len(x2)-1][0]:
72
x2[len(x2)-1] = (v[0], v[1]+x2[len(x2)-1][1])
73
else:
74
x2.append(v)
75
self._element_list = x2
76
else:
77
self._element_list = list(x) # make copy, so user can't accidentally change monoid.
78
79
else:
80
# TODO: should have some other checks here...
81
raise TypeError, "Argument x (= %s) is of the wrong type."%x
82
83
def __iter__(self):
84
"""
85
Returns an iterator which yields tuples of variable and exponent.
86
87
EXAMPLES::
88
89
sage: a = FreeMonoid(5, 'a').gens()
90
sage: list(a[0]*a[1]*a[4]**3*a[0])
91
[(a0, 1), (a1, 1), (a4, 3), (a0, 1)]
92
"""
93
gens=self.parent().gens()
94
return ((gens[index], exponent) \
95
for (index, exponent) in self._element_list)
96
97
## def __cmp__(left, right):
98
## """
99
## Compare two free monoid elements with the same parents.
100
101
## The ordering is the one on the underlying sorted list of
102
## (monomial,coefficients) pairs.
103
104
## EXAMPLES:
105
## sage: R.<x,y> = FreeMonoid(2)
106
## sage: x < y
107
## True
108
## sage: x * y < y * x
109
## True
110
## sage: x * y * x^2 < x * y * x^3
111
## True
112
## """
113
## return cmp(left._element_list, right._element_list)
114
115
def _repr_(self):
116
s = ""
117
v = self._element_list
118
x = self.parent().variable_names()
119
for i in range(len(v)):
120
if len(s) > 0: s += "*"
121
g = x[int(v[i][0])]
122
e = v[i][1]
123
if e == 1:
124
s += "%s"%g
125
else:
126
s += "%s^%s"%(g,e)
127
if len(s) == 0: s = "1"
128
return s
129
130
def _latex_(self):
131
r"""
132
Return latex representation of self.
133
134
EXAMPLES::
135
136
sage: F = FreeMonoid(3, 'a')
137
sage: z = F([(0,5),(1,2),(0,10),(0,2),(1,2)])
138
sage: z._latex_()
139
'a_{0}^{5}a_{1}^{2}a_{0}^{12}a_{1}^{2}'
140
sage: F, (alpha,beta,gamma) = FreeMonoid(3, 'alpha,beta,gamma').objgens()
141
sage: latex(alpha*beta*gamma)
142
\alpha\beta\gamma
143
"""
144
s = ""
145
v = self._element_list
146
x = self.parent().latex_variable_names()
147
for i in range(len(v)):
148
g = x[int(v[i][0])]
149
e = v[i][1]
150
if e == 1:
151
s += "%s"%(g,)
152
else:
153
s += "%s^{%s}"%(g,e)
154
if len(s) == 0: s = "1"
155
return s
156
157
def __call__(self, *x, **kwds):
158
"""
159
EXAMPLES::
160
161
sage: M.<x,y,z>=FreeMonoid(3)
162
sage: (x*y).subs(x=1,y=2,z=14)
163
2
164
sage: (x*y).subs({x:z,y:z})
165
z^2
166
sage: M1=MatrixSpace(ZZ,1,2)
167
sage: M2=MatrixSpace(ZZ,2,1)
168
sage: (x*y).subs({x:M1([1,2]),y:M2([3,4])})
169
[11]
170
171
sage: M.<x,y> = FreeMonoid(2)
172
sage: (x*y).substitute(x=1)
173
y
174
175
sage: M.<a> = FreeMonoid(1)
176
sage: a.substitute(a=5)
177
5
178
179
AUTHORS:
180
181
- Joel B. Mohler (2007-10-27)
182
"""
183
if kwds and x:
184
raise ValueError, "must not specify both a keyword and positional argument"
185
186
P = self.parent()
187
188
if kwds:
189
x = self.gens()
190
gens_dict = dict([(name, i) for i, name in enumerate(P.variable_names())])
191
for key, value in kwds.iteritems():
192
if key in gens_dict:
193
x[gens_dict[key]] = value
194
195
if isinstance(x[0],tuple):
196
x = x[0]
197
198
if len(x) != self.parent().ngens():
199
raise ValueError, "must specify as many values as generators in parent"
200
201
# I don't start with 0, because I don't want to preclude evaluation with
202
#arbitrary objects (e.g. matrices) because of funny coercion.
203
one = P.one_element()
204
result = None
205
for var_index, exponent in self._element_list:
206
# Take further pains to ensure that non-square matrices are not exponentiated.
207
replacement = x[var_index]
208
if exponent > 1:
209
c = replacement ** exponent
210
elif exponent == 1:
211
c = replacement
212
else:
213
c = one
214
215
if result is None:
216
result = c
217
else:
218
result *= c
219
220
if result is None:
221
return one
222
223
return result
224
225
def _mul_(self, y):
226
"""
227
Multiply 2 free monoid elements.
228
229
EXAMPLES::
230
231
sage: a = FreeMonoid(5, 'a').gens()
232
sage: x = a[0] * a[1] * a[4]**3
233
sage: y = a[4] * a[0] * a[1]
234
sage: x*y
235
a0*a1*a4^4*a0*a1
236
"""
237
M = self.parent()
238
z = M(1)
239
x_elt = self._element_list
240
y_elt = y._element_list
241
if len(x_elt) == 0:
242
z._element_list = y_elt
243
elif len(y_elt) == 0:
244
z._element_list = x_elt
245
else:
246
k = len(x_elt)-1
247
if x_elt[k][0] != y_elt[0][0]:
248
z._element_list = x_elt + y_elt
249
else:
250
m = (y_elt[0][0],x_elt[k][1]+y_elt[0][1])
251
z._element_list = x_elt[0:k] + [ m ] + y_elt[1:]
252
return z
253
254
def __len__(self):
255
"""
256
Return the number of products that occur in this monoid element.
257
For example, the length of the identity is 0, and the length of the
258
monoid `x_0^2x_1` is three.
259
260
EXAMPLES::
261
262
sage: F = FreeMonoid(3, 'a')
263
sage: z = F(1)
264
sage: len(z)
265
0
266
sage: a = F.gens()
267
sage: len(a[0]**2 * a[1])
268
3
269
"""
270
s = 0
271
for x in self._element_list:
272
s += x[1]
273
return s
274
275
def __cmp__(self,y):
276
## """
277
## The comparison operator, defined via x = self:
278
## x < y <=> x.__cmp__(y) == -1
279
## x == y <=> x.__cmp__(y) == 0
280
## x > y <=> x.__cmp__(y) == 1
281
## It is not possible to use __cmp__ to define a
282
## non-totally ordered poset.
283
## Question: How can the operators <, >, ==, !=,
284
## <=, and >= be defined for a general poset?
285
## N.B. An equal operator __equal__ may or may not
286
## have been introduced to define == and != but can
287
## not be used in conjunction with __cmp__.
288
## """
289
if not isinstance(y,FreeMonoidElement) or y.parent() != self.parent():
290
#raise TypeError, "Argument y (= %s) is of the wrong type."%y
291
return 1
292
n = len(self)
293
m = len(y)
294
if n < m:
295
return -1
296
elif m < n:
297
return 1
298
elif n == 0:
299
return 0 # n = m = 0 hence x = y = 1
300
x_elt = self._element_list
301
y_elt = y._element_list
302
for i in range(len(x_elt)):
303
k = x_elt[i][0]
304
l = y_elt[i][0]
305
if k < l:
306
return -1
307
elif k > l:
308
return 1
309
e = x_elt[i][1]
310
f = y_elt[i][1]
311
if e < f:
312
# x_elt is longer so compare next index
313
if x_elt[i+1][0] < l:
314
return -1
315
else:
316
return 1
317
elif f < e:
318
# y_elt is longer so compare next index
319
if k < y_elt[i+1][0]:
320
return -1
321
else:
322
return 1
323
return 0 # x = self and y are equal
324
325
326
def _acted_upon_(self, x, self_on_left):
327
"""
328
Currently, returns the action of the integer 1 on this
329
element.
330
331
EXAMPLES::
332
333
sage: M.<x,y,z>=FreeMonoid(3)
334
sage: 1*x
335
x
336
"""
337
if x == 1:
338
return self
339
return None
340
341