Path: blob/master/sage/combinat/combinatorial_algebra.py
4057 views
r"""1Combinatorial Algebras23A combinatorial algebra is an algebra whose basis elements are4indexed by a combinatorial class. Some examples of combinatorial5algebras are the symmetric group algebra of order n (indexed by6permutations of size n) and the algebra of symmetric functions7(indexed by integer partitions).89The CombinatorialAlgebra base class makes it easy to define and10work with new combinatorial algebras in Sage. For example, the11following code constructs an algebra which models the power-sum12symmetric functions.1314::1516sage: class PowerSums(CombinatorialAlgebra):17... def __init__(self, R):18... self._one = Partition([])19... self._name = 'Power-sum symmetric functions'20... CombinatorialAlgebra.__init__(self, R, Partitions())21... self.print_options(prefix='p')22...23... def _multiply_basis(self, a, b):24... l = list(a)+list(b)25... l.sort(reverse=True)26... return Partition(l)27...2829::3031sage: ps = PowerSums(QQ); ps32Power-sum symmetric functions over Rational Field33sage: ps([2,1])^234p[2, 2, 1, 1]35sage: ps([2,1])+2*ps([1,1,1])362*p[1, 1, 1] + p[2, 1]37sage: ps(2)382*p[]3940The important things to define are ._basis_keys which41specifies the combinatorial class that indexes the basis elements,42._one which specifies the identity element in the algebra, ._name43which specifies the name of the algebra, .print_options is used to set44the print options for the elements, and finally a _multiply45or _multiply_basis method that defines the multiplication in the46algebra.47"""48#*****************************************************************************49# Copyright (C) 2007 Mike Hansen <[email protected]>,50#51# Distributed under the terms of the GNU General Public License (GPL)52#53# This code is distributed in the hope that it will be useful,54# but WITHOUT ANY WARRANTY; without even the implied warranty of55# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU56# General Public License for more details.57#58# The full text of the GPL is available at:59#60# http://www.gnu.org/licenses/61#*****************************************************************************6263#from sage.algebras.algebra import Algebra64#from sage.algebras.algebra_element import AlgebraElement65from sage.combinat.free_module import CombinatorialFreeModule66from sage.misc.misc import repr_lincomb67from sage.misc.cachefunc import cached_method68from sage.categories.all import AlgebrasWithBasis6970# TODO: migrate this completely to the combinatorial free module + categories framework7172# for backward compatibility73CombinatorialAlgebraElement = CombinatorialFreeModule.Element7475# Not used anymore76class CombinatorialAlgebraElementOld(CombinatorialFreeModule.Element):77# def __init__(self, A, x):78# """79# Create a combinatorial algebra element x. This should never80# be called directly, but only through the parent combinatorial81# algebra's __call__ method.8283# TESTS:84# sage: s = SFASchur(QQ)85# sage: a = s._element_class(s, {Partition([2,1]):QQ(2)}); a86# 2*s[2, 1]87# sage: a == loads(dumps(a))88# True89# """90# AlgebraElement.__init__(self, A)91# self._monomial_coefficients = x929394def _mul_(self, y):95"""96EXAMPLES::9798sage: s = sage.combinat.combinatorial_algebra.TestAlgebra(QQ)99sage: a = s([2])100sage: a._mul_(a) #indirect doctest101s[2, 2] + s[3, 1] + s[4]102"""103return self.parent().product(self, y)104105106def __invert__(self):107"""108EXAMPLES::109110sage: s = sage.combinat.combinatorial_algebra.TestAlgebra(QQ)111sage: ~s(2)1121/2*s[]113sage: ~s([2,1])114Traceback (most recent call last):115...116ValueError: cannot invert self (= s[2, 1])117"""118mcs = self._monomial_coefficients119one = self.parent()._one120if len(mcs) == 1 and one in mcs:121return self.parent()( ~mcs[ one ] )122else:123raise ValueError, "cannot invert self (= %s)"%self124125126127128129def __repr__(self):130"""131EXAMPLES::132133sage: s = sage.combinat.combinatorial_algebra.TestAlgebra(QQ)134sage: a = 2 + s([3,2,1])135sage: print a.__repr__()1362*s[] + s[3, 2, 1]137"""138v = self._monomial_coefficients.items()139v.sort()140prefix = self.parent().prefix()141retur = repr_lincomb( [(prefix + repr(m), c) for m,c in v ], strip_one = True)142143class CombinatorialAlgebra(CombinatorialFreeModule):144"""145146Deprecated! Don't use!147148"""149150# For backward compatibility151@cached_method152def one_basis(self):153"""154TESTS::155156sage: s = sage.combinat.combinatorial_algebra.TestAlgebra(QQ)157sage: s.one_basis()158[]159"""160return self._one161162def __init__(self, R, cc = None, element_class = None, category = None):163"""164TESTS::165166sage: s = sage.combinat.combinatorial_algebra.TestAlgebra(QQ)167sage: TestSuite(s).run()168"""169#Check to make sure that the user defines the necessary170#attributes / methods to make the combinatorial module171#work172required = ['_one',]173for r in required:174if not hasattr(self, r):175raise ValueError, "%s is required"%r176if not hasattr(self, '_multiply') and not hasattr(self, '_multiply_basis'):177raise ValueError, "either _multiply or _multiply_basis is required"178179#Create a class for the elements of this combinatorial algebra180#We need to do this so to distinguish between element of different181#combinatorial algebras182# if element_class is None:183# if not hasattr(self, '_element_class'):184# class CAElement(CombinatorialAlgebraElement):185# pass186# self._element_class = CAElement187# else:188# self._element_class = element_class189190if category is None:191category = AlgebrasWithBasis(R)192193# for backward compatibility194if cc is None and hasattr(self, "_basis_keys"):195cc = self._basis_keys196assert(cc is not None)197198CombinatorialFreeModule.__init__(self, R, cc, element_class, category = category)199200# see sage.combinat.free_module._repr_term201# this emulates the _repr_ of CombinatorialAlgebraElement did not add brackets around the basis indices202_repr_option_bracket = False203204def __call__(self, x):205"""206TESTS::207208sage: s = sage.combinat.combinatorial_algebra.TestAlgebra(QQ)209sage: s([2])210s[2]211"""212try:213return CombinatorialFreeModule.__call__(self, x)214except TypeError:215pass216217R = self.base_ring()218eclass = self._element_class219#Coerce elements of the base ring220if not hasattr(x, 'parent'):221x = R(x)222if x.parent() == R:223if x == R(0):224return eclass(self, {})225else:226return eclass(self, {self._one:x})227#Coerce things that coerce into the base ring228elif R.has_coerce_map_from(x.parent()):229rx = R(x)230if rx == R(0):231return eclass(self, {})232else:233return eclass(self, {self._one:R(x)})234235raise TypeError, "do not know how to make x (= %s) an element of self (=%s)"%(x,self)236237def _an_element_impl(self):238"""239Returns an element of self, namely the unit element.240241EXAMPLES::242243sage: s = sage.combinat.combinatorial_algebra.TestAlgebra(QQ)244sage: s._an_element_impl()245s[]246sage: _.parent() is s247True248"""249return self._element_class(self, {self._one:self.base_ring()(1)})250251def _coerce_impl(self, x):252"""253EXAMPLES::254255sage: s = sage.combinat.combinatorial_algebra.TestAlgebra(QQ)256sage: s(2) # indirect doctest2572*s[]258"""259try:260R = x.parent()261if R.__class__ is self.__class__:262#Only perform the coercion if we can go from the base263#ring of x to the base ring of self264if self.base_ring().has_coerce_map_from( R.base_ring() ):265return self(x)266except AttributeError:267pass268269# any ring that coerces to the base ring270return self._coerce_try(x, [self.base_ring()])271272def product(self, left, right):273"""274Returns left\*right where left and right are elements of self.275product() uses either _multiply or _multiply basis to carry out276the actual multiplication.277278EXAMPLES::279280sage: s = sage.combinat.combinatorial_algebra.TestAlgebra(QQ)281sage: a = s([2])282sage: s.product(a,a)283s[2, 2] + s[3, 1] + s[4]284sage: ZS3 = SymmetricGroupAlgebra(ZZ, 3)285sage: a = 2 + ZS3([2,1,3])286sage: a*a2875*[1, 2, 3] + 4*[2, 1, 3]288sage: H3 = HeckeAlgebraSymmetricGroupT(QQ,3)289sage: j2 = H3.jucys_murphy(2)290sage: j2*j2291(q^3-q^2+q)*T[1, 2, 3] + (q^3-q^2+q-1)*T[2, 1, 3]292sage: X = SchubertPolynomialRing(ZZ)293sage: X([1,2,3])*X([2,1,3])294X[2, 1]295"""296A = left.parent()297ABR = A.base_ring()298ABRzero = ABR(0)299z_elt = {}300301#Do the case where the user specifies how to multiply basis elements302if hasattr(self, '_multiply_basis'):303for (left_m, left_c) in left._monomial_coefficients.iteritems():304for (right_m, right_c) in right._monomial_coefficients.iteritems():305res = self._multiply_basis(left_m, right_m)306coeffprod = left_c * right_c307#Handle the case where the user returns a dictionary308#where the keys are the monomials and the values are309#the coefficients. If res is not a dictionary, then310#it is assumed to be an element of self311if not isinstance(res, dict):312if isinstance(res, self._element_class):313res = res._monomial_coefficients314else:315z_elt[res] = z_elt.get(res, ABRzero) + coeffprod316continue317for m, c in res.iteritems():318z_elt[m] = z_elt.get(m, ABRzero) + coeffprod * c319320#We assume that the user handles the multiplication correctly on321#his or her own, and returns a dict with monomials as keys and322#coefficients as values323else:324m = self._multiply(left, right)325if isinstance(m, self._element_class):326return m327if not isinstance(m, dict):328z_elt = m.monomial_coefficients()329else:330z_elt = m331332#Remove all entries that are equal to 0333BR = self.base_ring()334zero = BR(0)335del_list = []336for m, c in z_elt.iteritems():337if c == zero:338del_list.append(m)339for m in del_list:340del z_elt[m]341342return self._from_dict(z_elt)343344class TestAlgebra(CombinatorialAlgebra):345346_name = "TestAlgebra"347348def __init__(self, R):349"""350TESTS::351352sage: s = sage.combinat.combinatorial_algebra.TestAlgebra(QQ)353sage: TestSuite(s).run()354"""355from sage.combinat.partition import Partition, Partitions356self._one = Partition([])357CombinatorialAlgebra.__init__(self, R, cc=Partitions())358359def _multiply_basis(self, part1, part2):360"""361TESTS::362363sage: s = sage.combinat.combinatorial_algebra.TestAlgebra(QQ)364sage: a = s([2])365sage: a._mul_(a) #indirect doctest366s[2, 2] + s[3, 1] + s[4]367"""368from sage.combinat.sf.sfa import SFASchur369S = SFASchur(self.base_ring())370return self.sum_of_terms(S(part1) * S(part2))371372def prefix(self):373"""374TESTS::375376sage: sa = sage.combinat.combinatorial_algebra.TestAlgebra(QQ)377sage: x = sa([2]); x # indirect doctest378s[2]379"""380return "s"381382383