Path: blob/master/src/sage/monoids/free_monoid_element.py
8815 views
"""1Monoid Elements23AUTHORS:45- David Kohel (2005-09-29)67Elements of free monoids are represented internally as lists of8pairs of integers.9"""1011#*****************************************************************************12# Copyright (C) 2005 David Kohel <[email protected]>13#14# Distributed under the terms of the GNU General Public License (GPL)15#16# This code is distributed in the hope that it will be useful,17# but WITHOUT ANY WARRANTY; without even the implied warranty18# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.19#20# See the GNU General Public License for more details; the full text21# is available at:22#23# http://www.gnu.org/licenses/24#*****************************************************************************2526from sage.rings.integer import Integer27from sage.structure.element import MonoidElement2829def is_FreeMonoidElement(x):30return isinstance(x, FreeMonoidElement)3132class FreeMonoidElement(MonoidElement):33"""34Element of a free monoid.3536EXAMPLES::3738sage: a = FreeMonoid(5, 'a').gens()39sage: x = a[0]*a[1]*a[4]**340sage: x**341a0*a1*a4^3*a0*a1*a4^3*a0*a1*a4^342sage: x**043144sage: x**(-1)45Traceback (most recent call last):46...47TypeError: bad operand type for unary ~: 'FreeMonoid_class_with_category.element_class'48"""49def __init__(self, F, x, check=True):50"""51Create the element `x` of the FreeMonoid `F`.5253This should typically be called by a FreeMonoid.54"""55MonoidElement.__init__(self, F)56if isinstance(x, (int, long, Integer)):57if x == 1:58self._element_list = []59else:60raise TypeError, "Argument x (= %s) is of the wrong type."%x61elif isinstance(x, list):62if check:63x2 = []64for v in x:65if not isinstance(v, tuple) and len(v) == 2:66raise TypeError, "x (= %s) must be a list of 2-tuples or 1."%x67if not (isinstance(v[0], (int,long,Integer)) and \68isinstance(v[1], (int,long,Integer))):69raise TypeError, "x (= %s) must be a list of 2-tuples of integers or 1."%x70if len(x2) > 0 and v[0] == x2[len(x2)-1][0]:71x2[len(x2)-1] = (v[0], v[1]+x2[len(x2)-1][1])72else:73x2.append(v)74self._element_list = x275else:76self._element_list = list(x) # make copy, so user can't accidentally change monoid.7778else:79# TODO: should have some other checks here...80raise TypeError, "Argument x (= %s) is of the wrong type."%x8182def __iter__(self):83"""84Returns an iterator which yields tuples of variable and exponent.8586EXAMPLES::8788sage: a = FreeMonoid(5, 'a').gens()89sage: list(a[0]*a[1]*a[4]**3*a[0])90[(a0, 1), (a1, 1), (a4, 3), (a0, 1)]91"""92gens=self.parent().gens()93return ((gens[index], exponent) \94for (index, exponent) in self._element_list)9596## def __cmp__(left, right):97## """98## Compare two free monoid elements with the same parents.99100## The ordering is the one on the underlying sorted list of101## (monomial,coefficients) pairs.102103## EXAMPLES:104## sage: R.<x,y> = FreeMonoid(2)105## sage: x < y106## True107## sage: x * y < y * x108## True109## sage: x * y * x^2 < x * y * x^3110## True111## """112## return cmp(left._element_list, right._element_list)113114def _repr_(self):115s = ""116v = self._element_list117x = self.parent().variable_names()118for i in range(len(v)):119if len(s) > 0: s += "*"120g = x[int(v[i][0])]121e = v[i][1]122if e == 1:123s += "%s"%g124else:125s += "%s^%s"%(g,e)126if len(s) == 0: s = "1"127return s128129def _latex_(self):130r"""131Return latex representation of self.132133EXAMPLES::134135sage: F = FreeMonoid(3, 'a')136sage: z = F([(0,5),(1,2),(0,10),(0,2),(1,2)])137sage: z._latex_()138'a_{0}^{5}a_{1}^{2}a_{0}^{12}a_{1}^{2}'139sage: F, (alpha,beta,gamma) = FreeMonoid(3, 'alpha,beta,gamma').objgens()140sage: latex(alpha*beta*gamma)141\alpha\beta\gamma142"""143s = ""144v = self._element_list145x = self.parent().latex_variable_names()146for i in range(len(v)):147g = x[int(v[i][0])]148e = v[i][1]149if e == 1:150s += "%s"%(g,)151else:152s += "%s^{%s}"%(g,e)153if len(s) == 0: s = "1"154return s155156def __call__(self, *x, **kwds):157"""158EXAMPLES::159160sage: M.<x,y,z>=FreeMonoid(3)161sage: (x*y).subs(x=1,y=2,z=14)1622163sage: (x*y).subs({x:z,y:z})164z^2165sage: M1=MatrixSpace(ZZ,1,2)166sage: M2=MatrixSpace(ZZ,2,1)167sage: (x*y).subs({x:M1([1,2]),y:M2([3,4])})168[11]169170sage: M.<x,y> = FreeMonoid(2)171sage: (x*y).substitute(x=1)172y173174sage: M.<a> = FreeMonoid(1)175sage: a.substitute(a=5)1765177178AUTHORS:179180- Joel B. Mohler (2007-10-27)181"""182if kwds and x:183raise ValueError, "must not specify both a keyword and positional argument"184185P = self.parent()186187if kwds:188x = self.gens()189gens_dict = dict([(name, i) for i, name in enumerate(P.variable_names())])190for key, value in kwds.iteritems():191if key in gens_dict:192x[gens_dict[key]] = value193194if isinstance(x[0],tuple):195x = x[0]196197if len(x) != self.parent().ngens():198raise ValueError, "must specify as many values as generators in parent"199200# I don't start with 0, because I don't want to preclude evaluation with201#arbitrary objects (e.g. matrices) because of funny coercion.202one = P.one_element()203result = None204for var_index, exponent in self._element_list:205# Take further pains to ensure that non-square matrices are not exponentiated.206replacement = x[var_index]207if exponent > 1:208c = replacement ** exponent209elif exponent == 1:210c = replacement211else:212c = one213214if result is None:215result = c216else:217result *= c218219if result is None:220return one221222return result223224def _mul_(self, y):225"""226Multiply 2 free monoid elements.227228EXAMPLES::229230sage: a = FreeMonoid(5, 'a').gens()231sage: x = a[0] * a[1] * a[4]**3232sage: y = a[4] * a[0] * a[1]233sage: x*y234a0*a1*a4^4*a0*a1235"""236M = self.parent()237z = M(1)238x_elt = self._element_list239y_elt = y._element_list240if len(x_elt) == 0:241z._element_list = y_elt242elif len(y_elt) == 0:243z._element_list = x_elt244else:245k = len(x_elt)-1246if x_elt[k][0] != y_elt[0][0]:247z._element_list = x_elt + y_elt248else:249m = (y_elt[0][0],x_elt[k][1]+y_elt[0][1])250z._element_list = x_elt[0:k] + [ m ] + y_elt[1:]251return z252253def __len__(self):254"""255Return the number of products that occur in this monoid element.256For example, the length of the identity is 0, and the length of the257monoid `x_0^2x_1` is three.258259EXAMPLES::260261sage: F = FreeMonoid(3, 'a')262sage: z = F(1)263sage: len(z)2640265sage: a = F.gens()266sage: len(a[0]**2 * a[1])2673268"""269s = 0270for x in self._element_list:271s += x[1]272return s273274def __cmp__(self,y):275## """276## The comparison operator, defined via x = self:277## x < y <=> x.__cmp__(y) == -1278## x == y <=> x.__cmp__(y) == 0279## x > y <=> x.__cmp__(y) == 1280## It is not possible to use __cmp__ to define a281## non-totally ordered poset.282## Question: How can the operators <, >, ==, !=,283## <=, and >= be defined for a general poset?284## N.B. An equal operator __equal__ may or may not285## have been introduced to define == and != but can286## not be used in conjunction with __cmp__.287## """288if not isinstance(y,FreeMonoidElement) or y.parent() != self.parent():289#raise TypeError, "Argument y (= %s) is of the wrong type."%y290return 1291n = len(self)292m = len(y)293if n < m:294return -1295elif m < n:296return 1297elif n == 0:298return 0 # n = m = 0 hence x = y = 1299x_elt = self._element_list300y_elt = y._element_list301for i in range(len(x_elt)):302k = x_elt[i][0]303l = y_elt[i][0]304if k < l:305return -1306elif k > l:307return 1308e = x_elt[i][1]309f = y_elt[i][1]310if e < f:311# x_elt is longer so compare next index312if x_elt[i+1][0] < l:313return -1314else:315return 1316elif f < e:317# y_elt is longer so compare next index318if k < y_elt[i+1][0]:319return -1320else:321return 1322return 0 # x = self and y are equal323324325def _acted_upon_(self, x, self_on_left):326"""327Currently, returns the action of the integer 1 on this328element.329330EXAMPLES::331332sage: M.<x,y,z>=FreeMonoid(3)333sage: 1*x334x335"""336if x == 1:337return self338return None339340def to_word(self, alph=None):341"""342Return ``self`` as a word.343344INPUT:345346- ``alph`` -- (optional) the alphabet which the result should347be specified in348349EXAMPLES::350351sage: M.<x,y,z> = FreeMonoid(3)352sage: a = x * x * y * x353sage: w = a.to_word(); w354word: xxyx355sage: w.to_monoid_element() == a356True357"""358from sage.combinat.words.finite_word import Words359gens = self.parent().gens()360if alph is None:361alph = gens362alph = map(str, alph)363W = Words(alph)364return W(sum([ [alph[gens.index(i[0])]] * i[1] for i in list(self) ], []))365366367368