Path: blob/master/src/sage/combinat/diagram_algebras.py
8815 views
r"""1Diagram and Partition Algebras23AUTHORS:45- Mike Hansen (2007): Initial version6- Stephen Doty, Aaron Lauve, George H. Seelinger (2012): Implementation of7partition, Brauer, Temperley--Lieb, and ideal partition algebras8"""910#*****************************************************************************11# Copyright (C) 2007 Mike Hansen <[email protected]>,12# 2012 Stephen Doty <[email protected]>,13# Aaron Lauve <[email protected]>,14# George H. Seelinger <[email protected]>15#16# Distributed under the terms of the GNU General Public License (GPL)17# http://www.gnu.org/licenses/18#*****************************************************************************1920from sage.categories.all import FiniteDimensionalAlgebrasWithBasis21from sage.structure.element import generic_power22from sage.combinat.free_module import (CombinatorialFreeModule,23CombinatorialFreeModuleElement)24from sage.combinat.set_partition import SetPartitions, SetPartition25from sage.sets.set import Set26from sage.graphs.graph import Graph27from sage.misc.cachefunc import cached_method28from sage.rings.all import ZZ29import math3031def partition_diagrams(k):32r"""33Return a list of all partition diagrams of order ``k``.3435A partition diagram of order `k \in \ZZ` to is a set partition of36`\{1, \dots, k, -1, \ldots, -k\}`. If we have `k - 1/2 \in ZZ`, then37a partition diagram of order `k \in 1/2 \ZZ` is a set partition of38`\{1, \ldots, k+1/2, -1, \ldots, -(k+1/2)\}` with `k+1/2` and `-(k+1/2)`39in the same block. See [HR2005]_.4041INPUT:4243- ``k`` -- the order of the partition diagrams4445EXAMPLES::4647sage: import sage.combinat.diagram_algebras as da48sage: da.partition_diagrams(2)49[{{-2, -1, 1, 2}}, {{-2, -1, 2}, {1}}, {{-2, -1, 1}, {2}},50{{-2}, {-1, 1, 2}}, {{-2, 1, 2}, {-1}}, {{-2, 1}, {-1, 2}},51{{-2, 2}, {-1, 1}}, {{-2, -1}, {1, 2}}, {{-2, -1}, {1}, {2}},52{{-2}, {-1, 2}, {1}}, {{-2, 2}, {-1}, {1}}, {{-2}, {-1, 1}, {2}},53{{-2, 1}, {-1}, {2}}, {{-2}, {-1}, {1, 2}}, {{-2}, {-1}, {1}, {2}}]54sage: da.partition_diagrams(3/2)55[{{-2, -1, 1, 2}}, {{-2, -1, 2}, {1}}, {{-2, 2}, {-1, 1}},56{{-2, 1, 2}, {-1}}, {{-2, 2}, {-1}, {1}}]57"""58if k in ZZ:59return SetPartitions( range(1, k+1) + [-j for j in range(1, k+1)] ).list()60# Else k in 1/2 ZZ61L = []62k += ZZ(1) / ZZ(2)63for sp in SetPartitions( range(1, k+1) + [-j for j in range(1, k)] ):64sp = list(sp)65for i in range(len(sp)):66if k in sp[i]:67sp[i] += Set([-k])68break69L.append(SetPartition(sp))70return L7172def brauer_diagrams(k):73r"""74Return a list of all Brauer diagrams of order ``k``.7576A Brauer diagram of order `k` is a partition diagram of order `k`77with block size 2.7879INPUT:8081- ``k`` -- the order of the Brauer diagrams8283EXAMPLES::8485sage: import sage.combinat.diagram_algebras as da86sage: da.brauer_diagrams(2)87[{{-2, 1}, {-1, 2}}, {{-2, 2}, {-1, 1}}, {{-2, -1}, {1, 2}}]88sage: da.brauer_diagrams(5/2)89[{{-3, 3}, {-2, 1}, {-1, 2}}, {{-3, 3}, {-2, 2}, {-1, 1}}, {{-3, 3}, {-2, -1}, {1, 2}}]90"""91if k in ZZ:92return [SetPartition(list(x)) for x in93SetPartitions( range(1,k+1) + [-j for j in range(1,k+1)],94[2 for j in range(1,k+1)] )]95# Else k in 1/2 ZZ96L = []97k += ZZ(1) / ZZ(2)98for i in SetPartitions( range(1, k) + [-j for j in range(1, k)],99[2 for j in range(1, k)] ):100L.append(SetPartition(list(i) + [Set([k, -k])]))101return L102103def temperley_lieb_diagrams(k):104r"""105Return a list of all Temperley--Lieb diagrams of order ``k``.106107A Temperley--Lieb diagram of order `k` is a partition diagram of order `k`108with block size 2 and is planar.109110INPUT:111112- ``k`` -- the order of the Temperley--Lieb diagrams113114EXAMPLES::115116sage: import sage.combinat.diagram_algebras as da117sage: da.temperley_lieb_diagrams(2)118[{{-2, 2}, {-1, 1}}, {{-2, -1}, {1, 2}}]119sage: da.temperley_lieb_diagrams(5/2)120[{{-3, 3}, {-2, 2}, {-1, 1}}, {{-3, 3}, {-2, -1}, {1, 2}}]121"""122B = brauer_diagrams(k)123T = []124for i in B:125if is_planar(i) == True:126T.append(i)127return T128129def planar_diagrams(k):130r"""131Return a list of all planar diagrams of order ``k``.132133A planar diagram of order `k` is a partition diagram of order `k`134that has no crossings.135136EXAMPLES::137138sage: import sage.combinat.diagram_algebras as da139sage: da.planar_diagrams(2)140[{{-2, -1, 1, 2}}, {{-2, -1, 2}, {1}}, {{-2, -1, 1}, {2}},141{{-2}, {-1, 1, 2}}, {{-2, 1, 2}, {-1}}, {{-2, 2}, {-1, 1}},142{{-2, -1}, {1, 2}}, {{-2, -1}, {1}, {2}}, {{-2}, {-1, 2}, {1}},143{{-2, 2}, {-1}, {1}}, {{-2}, {-1, 1}, {2}}, {{-2, 1}, {-1}, {2}},144{{-2}, {-1}, {1, 2}}, {{-2}, {-1}, {1}, {2}}]145sage: da.planar_diagrams(3/2)146[{{-2, -1, 1, 2}}, {{-2, -1, 2}, {1}}, {{-2, 2}, {-1, 1}},147{{-2, 1, 2}, {-1}}, {{-2, 2}, {-1}, {1}}]148"""149A = partition_diagrams(k)150P = []151for i in A:152if is_planar(i) == True:153P.append(i)154return P155156def ideal_diagrams(k):157r"""158Return a list of all "ideal" diagrams of order ``k``.159160An ideal diagram of order `k` is a partition diagram of order `k` with161propagating number less than `k`.162163EXAMPLES::164165sage: import sage.combinat.diagram_algebras as da166sage: da.ideal_diagrams(2)167[{{-2, -1, 1, 2}}, {{-2, -1, 2}, {1}}, {{-2, -1, 1}, {2}}, {{-2}, {-1, 1, 2}},168{{-2, 1, 2}, {-1}}, {{-2, -1}, {1, 2}}, {{-2, -1}, {1}, {2}},169{{-2}, {-1, 2}, {1}}, {{-2, 2}, {-1}, {1}}, {{-2}, {-1, 1}, {2}}, {{-2, 1},170{-1}, {2}}, {{-2}, {-1}, {1, 2}}, {{-2}, {-1}, {1}, {2}}]171sage: da.ideal_diagrams(3/2)172[{{-2, -1, 1, 2}}, {{-2, -1, 2}, {1}}, {{-2, 1, 2}, {-1}}, {{-2, 2}, {-1}, {1}}]173"""174A = partition_diagrams(k)175I = []176for i in A:177if propagating_number(i) < k:178I.append(i)179return I180181class DiagramAlgebra(CombinatorialFreeModule):182r"""183Abstract class for diagram algebras and is not designed to be used184directly. If used directly, the class could create an "algebra"185that is not actually an algebra.186187TESTS::188189sage: import sage.combinat.diagram_algebras as da190sage: R.<x> = QQ[]191sage: D = da.DiagramAlgebra(2, x, R, 'P', da.partition_diagrams)192sage: sorted(D.basis())193[P[{{-2}, {-1}, {1}, {2}}],194P[{{-2}, {-1}, {1, 2}}],195P[{{-2}, {-1, 1}, {2}}],196P[{{-2}, {-1, 1, 2}}],197P[{{-2}, {-1, 2}, {1}}],198P[{{-2, -1}, {1}, {2}}],199P[{{-2, -1}, {1, 2}}],200P[{{-2, -1, 1}, {2}}],201P[{{-2, -1, 1, 2}}],202P[{{-2, -1, 2}, {1}}],203P[{{-2, 1}, {-1}, {2}}],204P[{{-2, 1}, {-1, 2}}],205P[{{-2, 1, 2}, {-1}}],206P[{{-2, 2}, {-1}, {1}}],207P[{{-2, 2}, {-1, 1}}]]208"""209def __init__(self, k, q, base_ring, prefix, diagrams, category=None):210r"""211Initialize ``self``.212213INPUT:214215- ``k`` -- the rank216- ``q`` -- the deformation parameter217- ``base_ring`` -- the base ring218- ``prefix`` -- the prefix of our monomials219- ``diagrams`` -- the *function* which will generate all diagrams220(i.e. indices for the basis elements)221222TESTS::223224sage: import sage.combinat.diagram_algebras as da225sage: R.<x> = QQ[]226sage: D = da.DiagramAlgebra(2, x, R, 'P', da.partition_diagrams)227sage: TestSuite(D).run()228"""229self._prefix = prefix230self._q = base_ring(q)231self._k = k232if category is None:233category = FiniteDimensionalAlgebrasWithBasis(base_ring)234CombinatorialFreeModule.__init__(self, base_ring, diagrams(k),235category=category, prefix=prefix)236237def _element_constructor_(self, set_partition):238r"""239Construct an element of ``self``.240241TESTS::242243sage: import sage.combinat.diagram_algebras as da244sage: R.<x> = QQ[]245sage: D = da.DiagramAlgebra(2, x, R, 'P', da.partition_diagrams)246sage: sp = da.to_set_partition( [[1,2], [-1,-2]] )247sage: b_elt = D(sp); b_elt248P[{{-2, -1}, {1, 2}}]249sage: b_elt in D250True251sage: D([[1,2],[-1,-2]]) == b_elt252True253sage: D([{1,2},{-1,-2}]) == b_elt254True255"""256if set_partition in self.basis().keys():257return CombinatorialFreeModule._element_constructor_(self, set_partition)258259sp = SetPartition(set_partition) # attempt conversion260if sp in self.basis().keys():261return self.basis()[sp]262263raise ValueError("invalid input of {0}".format(set_partition))264265def __getitem__(self, i):266"""267Get the basis item of ``self`` indexed by ``i``.268269EXAMPLES::270271sage: import sage.combinat.diagram_algebras as da272sage: R.<x> = QQ[]273sage: D = da.DiagramAlgebra(2, x, R, 'P', da.partition_diagrams)274sage: sp = da.to_set_partition( [[1,2], [-1,-2]] )275sage: D[sp]276P[{{-2, -1}, {1, 2}}]277"""278i = to_set_partition(i)279if i in self.basis().keys():280return self.basis()[i]281raise ValueError("{0} is not an index of a basis element".format(i))282283def order(self):284r"""285Return the order of ``self``.286287The order of a partition algebra is defined as half of the number288of nodes in the diagrams.289290EXAMPLES::291292sage: q = var('q')293sage: PA = PartitionAlgebra(2, q)294sage: PA.order()2952296"""297return self._k298299def set_partitions(self):300r"""301Return the collection of underlying set partitions indexing the302basis elements of a given diagram algebra.303304TESTS::305306sage: import sage.combinat.diagram_algebras as da307sage: R.<x> = QQ[]308sage: D = da.DiagramAlgebra(2, x, R, 'P', da.partition_diagrams)309sage: list(D.set_partitions()) == da.partition_diagrams(2)310True311"""312return self.basis().keys()313314def product_on_basis(self, d1, d2):315r"""316Returns the product `D_{d_1} D_{d_2}` by two basis diagrams.317318TESTS::319320sage: import sage.combinat.diagram_algebras as da321sage: R.<x> = QQ[]322sage: D = da.DiagramAlgebra(2, x, R, 'P', da.partition_diagrams)323sage: sp = SetPartition([[1,2],[-1,-2]])324sage: D.product_on_basis(sp, sp)325x*P[{{-2, -1}, {1, 2}}]326"""327(composite_diagram, loops_removed) = set_partition_composition(d1, d2)328return self.term(composite_diagram, self._q**loops_removed)329330@cached_method331def one_basis(self):332r"""333The following constructs the identity element of the diagram algebra.334335It is not called directly; instead one should use ``DA.one()`` if336``DA`` is a defined diagram algebra.337338EXAMPLES::339340sage: import sage.combinat.diagram_algebras as da341sage: R.<x> = QQ[]342sage: D = da.DiagramAlgebra(2, x, R, 'P', da.partition_diagrams)343sage: D.one_basis()344{{-2, 2}, {-1, 1}}345"""346return identity_set_partition(self._k)347348# The following subclass provides a few additional methods for349# partition algebra elements.350class Element(CombinatorialFreeModuleElement):351r"""352This subclass provides a few additional methods for353partition algebra elements. Most element methods are354already implemented elsewhere.355"""356def diagram(self):357r"""358Return the underlying diagram of ``self`` if ``self`` is a basis359element. Raises an error if ``self`` is not a basis element.360361EXAMPLES::362363sage: R.<x> = ZZ[]364sage: P = PartitionAlgebra(2, x, R)365sage: elt = 3*P([[1,2],[-2,-1]])366sage: elt.diagram()367{{-2, -1}, {1, 2}}368"""369if len(self) != 1:370raise ValueError("this is only defined for basis elements")371PA = self.parent()372ans = self.support_of_term()373if ans not in partition_diagrams(PA.order()):374raise ValueError("element should be keyed by a diagram")375return ans376377def diagrams(self):378r"""379Return the diagrams in the support of ``self``.380381EXAMPLES::382383sage: R.<x> = ZZ[]384sage: P = PartitionAlgebra(2, x, R)385sage: elt = 3*P([[1,2],[-2,-1]]) + P([[1,2],[-2], [-1]])386sage: elt.diagrams()387[{{-2}, {-1}, {1, 2}}, {{-2, -1}, {1, 2}}]388"""389return self.support()390391def _latex_(self):392r"""393Return `\LaTeX` representation of ``self`` to draw single394diagrams in latex using tikz.395396EXAMPLES::397398sage: R.<x> = ZZ[]399sage: P = PartitionAlgebra(2, x, R)400sage: latex(P([[1,2],[-2,-1]]))401\begin{tikzpicture}[scale = 0.9,thick]402\tikzstyle{vertex} = [shape = circle, minimum size = 9pt, inner sep = 1pt]403\node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {};404\node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {};405\node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {};406\node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {};407\draw (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1);408\draw (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2);409\end{tikzpicture}410"""411# these allow the view command to work (maybe move them somewhere more appropriate?)412from sage.misc.latex import latex413latex.add_to_mathjax_avoid_list('tikzpicture')414latex.add_package_to_preamble_if_available('tikz')415416# Define the sign function417def sgn(x):418if x > 0:419return 1420if x < 0:421return -1422return 0423diagram = self.diagram()424l1 = [] #list of blocks425l2 = [] #lsit of nodes426for i in list(diagram):427l1.append(list(i))428for j in list(i):429l2.append(j)430#setup beginning of picture431output = "\\begin{tikzpicture}[scale = 0.9,thick] \n\\tikzstyle{vertex} = [shape = circle, minimum size = 9pt, inner sep = 1pt] \n"432for i in l2: #add nodes433output = output + "\\node[vertex] (G-%s) at (%s, %s) [shape = circle, draw] {}; \n" % (i, (abs(i)-1)*1.5, sgn(i))434for i in l1: #add edges435if (len(i) > 1):436l4 = list(i)437posList = []438negList = []439for i in l4: #sort list so rows are grouped together440if i > 0:441posList.append(i)442elif i < 0:443negList.append(i)444posList.sort()445negList.sort()446l4 = posList + negList447l5 = l4[:] #deep copy448for j in range(len(l5)):449l5[j-1] = l4[j] #create a permuted list450if (len(l4) == 2):451l4.pop()452l5.pop() #pops to prevent duplicating edges453for j in zip(l4, l5):454xdiff = abs(j[1])-abs(j[0])455y1 = sgn(j[0])456y2 = sgn(j[1])457if ((y2-y1) == 0 and abs(xdiff) < 5): #if nodes are close to each other on same row458diffCo = (0.5+0.1*(abs(xdiff)-1)) #gets bigger as nodes are farther apart; max value of 1; min value of 0.5.459outVec = (sgn(xdiff)*diffCo, -1*diffCo*y1)460inVec = (-1*diffCo*sgn(xdiff), -1*diffCo*y2)461elif ((y2-y1) != 0 and abs(xdiff) == 1): #if nodes are close enough curviness looks bad.462outVec = (sgn(xdiff)*0.75, -1*y1)463inVec = (-1*sgn(xdiff)*0.75, -1*y2)464else:465outVec = (sgn(xdiff)*1, -1*y1)466inVec = (-1*sgn(xdiff), -1*y2)467output = output + "\\draw (G-%s) .. controls +%s and +%s .. (G-%s); \n" % (j[0], outVec, inVec,j[1])468output = output + "\\end{tikzpicture}" #end picture469return output470471class PartitionAlgebra(DiagramAlgebra):472r"""473A partition algebra.474475The partition algebra of rank `k` is an algebra with basis indexed by the476collection of set partitions of `\{1, \dots, k, -1, \ldots, -k\}`. Each477such set partition is regarded as a graph on nodes `\{1, \ldots, k, -1,478\ldots, -k\}` arranged in two rows, with nodes `1, \dots, k` in the top479row from left to right and with nodes `-1, \ldots, -k` in the bottom row480from left to right, and an edge connecting two nodes if and only if the481nodes lie in the same subset of the set partition.482483The partition algebra is regarded as an example of a "diagram algebra" due484to the fact that its natural basis is given by certain graphs often called485diagrams.486487The product of two basis elements is given by the rule488`a \cdot b = q^N (a \circ b)`, where `a \circ b` is the composite set489partition obtained by placing diagram `a` above diagram `b`, identifying490the bottom row nodes of `a` with the top row nodes of `b`, and omitting491any closed "loops" in the middle. The number `N` is the number of492connected components of the omitted loops.493494The parameter `q` is a deformation parameter. Taking `q = 1` produces the495semigroup algebra (over the base ring) of the partition monoid, in which496the product of two set partitions is simply given by their composition.497498The Iwahori--Hecke algebra of type `A` (with a single parameter) is499naturally a subalgebra of the partition algebra.500501An excellent reference for partition algebras and its various subalgebras502(Brauer algebra, Temperley--Lieb algebra, etc) is the paper [HR2005]_.503504INPUT:505506- ``k``-- rank of the algebra507508- ``q``-- the deformation parameter `q`509510OPTIONAL ARGUMENTS:511512- ``base_ring``-- (default ``None``) a ring containing ``q``; if ``None``513then just takes the parent of ``q``514515- ``prefix``-- (default ``"P"``) a label for the basis elements516517EXAMPLES:518519The following shorthand simultaneously define the univariate polynomial520ring over the rationals as well as the variable ``x``::521522sage: R.<x> = PolynomialRing(QQ)523sage: R524Univariate Polynomial Ring in x over Rational Field525sage: x526x527sage: x.parent() is R528True529530We now define the partition algebra of rank `2` with parameter ``x``531over `\ZZ`::532533sage: R.<x> = ZZ[]534sage: P = PartitionAlgebra(2, x, R)535sage: P536Partition Algebra of rank 2 with parameter x over Univariate Polynomial Ring in x over Integer Ring537sage: P.basis().list()538[P[{{-2, -1, 1, 2}}], P[{{-2, -1, 2}, {1}}],539P[{{-2, -1, 1}, {2}}], P[{{-2}, {-1, 1, 2}}],540P[{{-2, 1, 2}, {-1}}], P[{{-2, 1}, {-1, 2}}],541P[{{-2, 2}, {-1, 1}}], P[{{-2, -1}, {1, 2}}],542P[{{-2, -1}, {1}, {2}}], P[{{-2}, {-1, 2}, {1}}],543P[{{-2, 2}, {-1}, {1}}], P[{{-2}, {-1, 1}, {2}}],544P[{{-2, 1}, {-1}, {2}}], P[{{-2}, {-1}, {1, 2}}],545P[{{-2}, {-1}, {1}, {2}}]]546sage: E = P([[1,2],[-2,-1]]); E547P[{{-2, -1}, {1, 2}}]548sage: E in P.basis()549True550sage: E^2551x*P[{{-2, -1}, {1, 2}}]552sage: E^5553x^4*P[{{-2, -1}, {1, 2}}]554sage: (P([[2,-2],[-1,1]]) - 2*P([[1,2],[-1,-2]]))^2555(4*x-4)*P[{{-2, -1}, {1, 2}}] + P[{{-2, 2}, {-1, 1}}]556557One can work with partition algebras using a symbol for the parameter,558leaving the base ring unspecified. This implies that the underlying559base ring is Sage's symbolic ring.560561::562563sage: q = var('q')564sage: PA = PartitionAlgebra(2, q); PA565Partition Algebra of rank 2 with parameter q over Symbolic Ring566sage: PA([[1,2],[-2,-1]])^2 == q*PA([[1,2],[-2,-1]])567True568sage: (PA([[2, -2], [1, -1]]) - 2*PA([[-2, -1], [1, 2]]))^2 == (4*q-4)*PA([[1, 2], [-2, -1]]) + PA([[2, -2], [1, -1]])569True570571The identity element of the partition algebra is the diagram whose set572partition is `\{\{1,-1\}, \{2,-2\}, \ldots, \{k,-k\}\}`::573574sage: P = PA.basis().list()575sage: PA.one()576P[{{-2, 2}, {-1, 1}}]577sage: PA.one()*P[7] == P[7]578True579sage: P[7]*PA.one() == P[7]580True581582We now give some further examples of the use of the other arguments.583One may wish to "specialize" the parameter to a chosen element of584the base ring::585586sage: R.<q> = RR[]587sage: PA = PartitionAlgebra(2, q, R, prefix='B')588sage: PA589Partition Algebra of rank 2 with parameter q over590Univariate Polynomial Ring in q over Real Field with 53 bits of precision591sage: PA([[1,2],[-1,-2]])5921.00000000000000*B[{{-2, -1}, {1, 2}}]593sage: PA = PartitionAlgebra(2, 5, base_ring=ZZ, prefix='B')594sage: PA595Partition Algebra of rank 2 with parameter 5 over Integer Ring596sage: (PA([[2, -2], [1, -1]]) - 2*PA([[-2, -1], [1, 2]]))^2 == 16*PA([[-2, -1], [1, 2]]) + PA([[2, -2], [1, -1]])597True598599REFERENCES:600601.. [HR2005] Tom Halverson and Arun Ram, *Partition algebras*. European602Journal of Combinatorics **26** (2005), 869--921.603"""604@staticmethod605def __classcall_private__(cls, k, q, base_ring=None, prefix="P"):606r"""607Standardize the input by getting the base ring from the parent of608the parameter ``q`` if no ``base_ring`` is given.609610TESTS::611612sage: R.<q> = QQ[]613sage: PA1 = PartitionAlgebra(2, q)614sage: PA2 = PartitionAlgebra(2, q, R, 'P')615sage: PA1 is PA2616True617"""618if base_ring is None:619base_ring = q.parent()620return super(PartitionAlgebra, cls).__classcall__(cls, k, q, base_ring, prefix)621622# The following is the basic constructor method for the class.623# The purpose of the "prefix" is to label the basis elements624def __init__(self, k, q, base_ring, prefix):625r"""626Initialize ``self``.627628TESTS::629630sage: R.<q> = QQ[]631sage: PA = PartitionAlgebra(2, q, R)632sage: TestSuite(PA).run()633"""634self._k = k635self._prefix = prefix636self._q = base_ring(q)637DiagramAlgebra.__init__(self, k, q, base_ring, prefix, partition_diagrams)638639def _repr_(self):640"""641Return a string representation of ``self``.642643EXAMPLES::644645sage: R.<q> = QQ[]646sage: PartitionAlgebra(2, q, R)647Partition Algebra of rank 2 with parameter q over Univariate Polynomial Ring in q over Rational Field648"""649return "Partition Algebra of rank %s with parameter %s over %s"%(self._k,650self._q, self.base_ring())651652class SubPartitionAlgebra(DiagramAlgebra):653"""654A subalgebra of the partition algebra indexed by a subset of the diagrams.655"""656def __init__(self, k, q, base_ring, prefix, diagrams, category=None):657"""658Initialize ``self`` by adding a coercion to the ambient space.659660EXAMPLES::661662sage: R.<x> = QQ[]663sage: BA = BrauerAlgebra(2, x, R)664sage: BA.ambient().has_coerce_map_from(BA)665True666"""667DiagramAlgebra.__init__(self, k, q, base_ring, prefix, diagrams, category)668amb = self.ambient()669self.module_morphism(self.lift, codomain=amb,670category=self.category()).register_as_coercion()671672#These methods allow for a sub algebra to be correctly identified in a partition algebra673def ambient(self):674r"""675Return the partition algebra ``self`` is a sub-algebra of.676Generally, this method is not called directly.677678EXAMPLES::679680sage: x = var('x')681sage: BA = BrauerAlgebra(2, x)682sage: BA.ambient()683Partition Algebra of rank 2 with parameter x over Symbolic Ring684"""685return PartitionAlgebra(self._k, self._q, self.base_ring(), prefix=self._prefix)686687def lift(self, x):688r"""689Lift a diagram subalgebra element to the corresponding element690in the ambient space. This method is not intended to be called691directly.692693EXAMPLES::694695sage: R.<x> = QQ[]696sage: BA = BrauerAlgebra(2, x, R)697sage: E = BA([[1,2],[-1,-2]])698sage: lifted = BA.lift(E); lifted699B[{{-2, -1}, {1, 2}}]700sage: lifted.parent() is BA.ambient()701True702"""703if x not in self:704raise ValueError("{0} is not in {1}".format(x, self))705monomial_indices = x.support()706monomial_coefficients = x.coefficients()707result = 0708for i in xrange(len(monomial_coefficients)):709result += monomial_coefficients[i]*self.ambient().monomial(monomial_indices[i])710return result711712def retract(self, x):713r"""714Retract an appropriate partition algebra element to the715corresponding element in the partition subalgebra. This method716is not intended to be called directly.717718EXAMPLES::719720sage: R.<x> = QQ[]721sage: BA = BrauerAlgebra(2, x, R)722sage: PA = BA.ambient()723sage: E = PA([[1,2], [-1,-2]])724sage: BA.retract(E) in BA725True726"""727if x not in self.ambient() or not set(x.support()).issubset(set(self.basis().keys())):728raise ValueError("{0} cannot retract to {1}".format(x, self))729monomial_indices = x.support()730monomial_coefficients = x.coefficients()731result = self.zero()732for i in xrange(len(monomial_coefficients)):733result += monomial_coefficients[i]*self.monomial(monomial_indices[i])734return result735736class BrauerAlgebra(SubPartitionAlgebra):737r"""738A Brauer algebra.739740The Brauer algebra of rank `k` is an algebra with basis indexed by the741collection of set partitions of `\{1, \ldots, k, -1, \ldots, -k\}`742with block size 2.743744This algebra is a subalgebra of the partition algebra.745For more information, see :class:`PartitionAlgebra`.746747INPUT:748749- ``k``-- rank of the algebra750751- ``q``-- the deformation parameter `q`752753OPTIONAL ARGUMENTS:754755- ``base_ring``-- (default ``None``) a ring containing ``q``; if ``None``756then just takes the parent of ``q``757758- ``prefix``-- (default ``"B"``) a label for the basis elements759760EXAMPLES:761762We now define the Brauer algebra of rank `2` with parameter ``x`` over763`\ZZ`::764765sage: R.<x> = ZZ[]766sage: B = BrauerAlgebra(2, x, R)767sage: B768Brauer Algebra of rank 2 with parameter x over Univariate Polynomial Ring in x over Integer Ring769sage: B.basis()770Finite family {{{-2, -1}, {1, 2}}: B[{{-2, -1}, {1, 2}}], {{-2, 1}, {-1, 2}}: B[{{-2, 1}, {-1, 2}}], {{-2, 2}, {-1, 1}}: B[{{-2, 2}, {-1, 1}}]}771sage: b = B.basis().list()772sage: b773[B[{{-2, 1}, {-1, 2}}], B[{{-2, 2}, {-1, 1}}], B[{{-2, -1}, {1, 2}}]]774sage: b[2]775B[{{-2, -1}, {1, 2}}]776sage: b[2]^2777x*B[{{-2, -1}, {1, 2}}]778sage: b[2]^5779x^4*B[{{-2, -1}, {1, 2}}]780"""781@staticmethod782def __classcall_private__(cls, k, q, base_ring=None, prefix="B"):783r"""784Standardize the input by getting the base ring from the parent of785the parameter ``q`` if no ``base_ring`` is given.786787TESTS::788789sage: R.<q> = QQ[]790sage: BA1 = BrauerAlgebra(2, q)791sage: BA2 = BrauerAlgebra(2, q, R, 'B')792sage: BA1 is BA2793True794"""795if base_ring is None:796base_ring = q.parent()797return super(BrauerAlgebra, cls).__classcall__(cls, k, q, base_ring, prefix)798799def __init__(self, k, q, base_ring, prefix):800r"""801Initialize ``self``.802803TESTS::804805sage: R.<q> = QQ[]806sage: BA = BrauerAlgebra(2, q, R)807sage: TestSuite(BA).run()808"""809SubPartitionAlgebra.__init__(self, k, q, base_ring, prefix, brauer_diagrams)810811def _repr_(self):812"""813Return a string representation of ``self``.814815EXAMPLES::816817sage: R.<q> = QQ[]818sage: BrauerAlgebra(2, q, R)819Brauer Algebra of rank 2 with parameter q over Univariate Polynomial Ring in q over Rational Field820"""821return "Brauer Algebra of rank %s with parameter %s over %s"%(self._k, self._q, self.base_ring())822823def _element_constructor_(self, set_partition):824r"""825Construct an element of ``self``.826827EXAMPLES::828829sage: R.<q> = QQ[]830sage: BA = BrauerAlgebra(2, q, R)831sage: sp = SetPartition([[1,2], [-1,-2]])832sage: b_elt = BA(sp); b_elt833B[{{-2, -1}, {1, 2}}]834sage: b_elt in BA835True836sage: BA([[1,2],[-1,-2]]) == b_elt837True838sage: BA([{1,2},{-1,-2}]) == b_elt839True840"""841set_partition = to_Brauer_partition(set_partition, k = self.order())842return DiagramAlgebra._element_constructor_(self, set_partition)843844class TemperleyLiebAlgebra(SubPartitionAlgebra):845r"""846A Temperley--Lieb algebra.847848The Temperley--Lieb algebra of rank `k` is an algebra with basis indexed849by the collection of planar set partitions of `\{1, \ldots, k, -1,850\ldots, -k\}` with block size 2.851852This algebra is thus a subalgebra of the partition algebra.853For more information, see :class:`PartitionAlgebra`.854855INPUT:856857- ``k``-- rank of the algebra858859- ``q``-- the deformation parameter `q`860861OPTIONAL ARGUMENTS:862863- ``base_ring``-- (default ``None``) a ring containing ``q``; if ``None``864then just takes the parent of ``q``865866- ``prefix``-- (default ``"T"``) a label for the basis elements867868EXAMPLES:869870We define the Temperley--Lieb algebra of rank `2` with parameter871`x` over `\ZZ`::872873sage: R.<x> = ZZ[]874sage: T = TemperleyLiebAlgebra(2, x, R); T875Temperley-Lieb Algebra of rank 2 with parameter x over Univariate Polynomial Ring in x over Integer Ring876sage: T.basis()877Finite family {{{-2, 2}, {-1, 1}}: T[{{-2, 2}, {-1, 1}}], {{-2, -1}, {1, 2}}: T[{{-2, -1}, {1, 2}}]}878sage: b = T.basis().list()879sage: b880[T[{{-2, 2}, {-1, 1}}], T[{{-2, -1}, {1, 2}}]]881sage: b[1]882T[{{-2, -1}, {1, 2}}]883sage: b[1]^2 == x*b[1]884True885sage: b[1]^5 == x^4*b[1]886True887"""888@staticmethod889def __classcall_private__(cls, k, q, base_ring=None, prefix="T"):890r"""891Standardize the input by getting the base ring from the parent of892the parameter ``q`` if no ``base_ring`` is given.893894TESTS::895896sage: R.<q> = QQ[]897sage: T1 = TemperleyLiebAlgebra(2, q)898sage: T2 = TemperleyLiebAlgebra(2, q, R, 'T')899sage: T1 is T2900True901"""902if base_ring is None:903base_ring = q.parent()904return super(TemperleyLiebAlgebra, cls).__classcall__(cls, k, q, base_ring, prefix)905906def __init__(self, k, q, base_ring, prefix):907r"""908Initialize ``self``909910TESTS::911912sage: R.<q> = QQ[]913sage: TL = TemperleyLiebAlgebra(2, q, R)914sage: TestSuite(TL).run()915"""916SubPartitionAlgebra.__init__(self, k, q, base_ring, prefix, temperley_lieb_diagrams)917918def _repr_(self):919"""920Return a string represetation of ``self``.921922EXAMPLES::923924sage: R.<q> = QQ[]925sage: TemperleyLiebAlgebra(2, q, R)926Temperley-Lieb Algebra of rank 2 with parameter q over Univariate Polynomial Ring in q over Rational Field927"""928return "Temperley-Lieb Algebra of rank %s with parameter %s over %s"%(self._k,929self._q, self.base_ring())930931def _element_constructor_(self, set_partition):932r"""933Construct an element of ``self``.934935EXAMPLES::936937sage: R.<q> = QQ[]938sage: TL = TemperleyLiebAlgebra(2, q, R)939sage: sp = SetPartition([[1,2], [-1,-2]])940sage: b_elt = TL(sp); b_elt941T[{{-2, -1}, {1, 2}}]942sage: b_elt in TL943True944sage: TL([[1,2],[-1,-2]]) == b_elt945True946sage: TL([{1,2},{-1,-2}]) == b_elt947True948"""949set_partition = to_Brauer_partition(set_partition, k = self.order())950return SubPartitionAlgebra._element_constructor_(self, set_partition)951952class PlanarAlgebra(SubPartitionAlgebra):953"""954A planar algebra.955956The planar algebra of rank `k` is an algebra with basis indexed by the957collection of set partitions of `\{1, \ldots, k, -1, \ldots, -k\}`958where each set partition is planar.959960This algebra is thus a subalgebra of the partition algebra. For more961information, see :class:`PartitionAlgebra`.962963INPUT:964965- ``k``-- rank of the algebra966967- ``q``-- the deformation parameter `q`968969OPTIONAL ARGUMENTS:970971- ``base_ring``-- (default ``None``) a ring containing ``q``; if ``None``972then just takes the parent of ``q``973974- ``prefix``-- (default ``"Pl"``) a label for the basis elements975976EXAMPLES:977978We now define the planar algebra of rank `2` with parameter979`x` over `\ZZ`::980981sage: R.<x> = ZZ[]982sage: Pl = PlanarAlgebra(2, x, R); Pl983Planar Algebra of rank 2 with parameter x over Univariate Polynomial Ring in x over Integer Ring984sage: Pl.basis().list()985[Pl[{{-2, -1, 1, 2}}], Pl[{{-2, -1, 2}, {1}}],986Pl[{{-2, -1, 1}, {2}}], Pl[{{-2}, {-1, 1, 2}}],987Pl[{{-2, 1, 2}, {-1}}], Pl[{{-2, 2}, {-1, 1}}],988Pl[{{-2, -1}, {1, 2}}], Pl[{{-2, -1}, {1}, {2}}],989Pl[{{-2}, {-1, 2}, {1}}], Pl[{{-2, 2}, {-1}, {1}}],990Pl[{{-2}, {-1, 1}, {2}}], Pl[{{-2, 1}, {-1}, {2}}],991Pl[{{-2}, {-1}, {1, 2}}], Pl[{{-2}, {-1}, {1}, {2}}]]992sage: E = Pl([[1,2],[-1,-2]])993sage: E^2 == x*E994True995sage: E^5 == x^4*E996True997"""998@staticmethod999def __classcall_private__(cls, k, q, base_ring=None, prefix="Pl"):1000r"""1001Standardize the input by getting the base ring from the parent of1002the parameter ``q`` if no ``base_ring`` is given.10031004TESTS::10051006sage: R.<q> = QQ[]1007sage: Pl1 = PlanarAlgebra(2, q)1008sage: Pl2 = PlanarAlgebra(2, q, R, 'Pl')1009sage: Pl1 is Pl21010True1011"""1012if base_ring is None:1013base_ring = q.parent()1014return super(PlanarAlgebra, cls).__classcall__(cls, k, q, base_ring, prefix)10151016def __init__(self, k, q, base_ring, prefix):1017r"""1018Initialize ``self``.10191020TESTS::10211022sage: R.<q> = QQ[]1023sage: PlA = PlanarAlgebra(2, q, R)1024sage: TestSuite(PlA).run()1025"""1026SubPartitionAlgebra.__init__(self, k, q, base_ring, prefix, planar_diagrams)10271028def _repr_(self):1029"""1030Return a string representation of ``self``.10311032EXAMPLES::10331034sage: R.<x> = ZZ[]1035sage: Pl = PlanarAlgebra(2, x, R); Pl1036Planar Algebra of rank 2 with parameter x over Univariate Polynomial Ring in x over Integer Ring1037"""1038return "Planar Algebra of rank %s with parameter %s over %s"%(self._k,1039self._q, self.base_ring())10401041class PropagatingIdeal(SubPartitionAlgebra):1042r"""1043A propagating ideal.10441045The propagating ideal of rank `k` is a non-unital algebra with basis1046indexed by the collection of ideal set partitions of `\{1, \ldots, k, -1,1047\ldots, -k\}`. We say a set partition is *ideal* if its propagating1048number is less than `k`.10491050This algebra is a non-unital subalgebra and an ideal of the partition1051algebra.1052For more information, see :class:`PartitionAlgebra`.10531054EXAMPLES:10551056We now define the propagating ideal of rank `2` with parameter1057`x` over `\ZZ`::10581059sage: R.<x> = QQ[]1060sage: I = PropagatingIdeal(2, x, R); I1061Propagating Ideal of rank 2 with parameter x over Univariate Polynomial Ring in x over Rational Field1062sage: I.basis().list()1063[I[{{-2, -1, 1, 2}}], I[{{-2, -1, 2}, {1}}],1064I[{{-2, -1, 1}, {2}}], I[{{-2}, {-1, 1, 2}}],1065I[{{-2, 1, 2}, {-1}}], I[{{-2, -1}, {1, 2}}],1066I[{{-2, -1}, {1}, {2}}], I[{{-2}, {-1, 2}, {1}}],1067I[{{-2, 2}, {-1}, {1}}], I[{{-2}, {-1, 1}, {2}}],1068I[{{-2, 1}, {-1}, {2}}], I[{{-2}, {-1}, {1, 2}}],1069I[{{-2}, {-1}, {1}, {2}}]]1070sage: E = I([[1,2],[-1,-2]])1071sage: E^2 == x*E1072True1073sage: E^5 == x^4*E1074True1075"""1076@staticmethod1077def __classcall_private__(cls, k, q, base_ring=None, prefix="I"):1078r"""1079Standardize the input by getting the base ring from the parent of1080the parameter ``q`` if no ``base_ring`` is given.10811082TESTS::10831084sage: R.<q> = QQ[]1085sage: IA1 = PropagatingIdeal(2, q)1086sage: IA2 = PropagatingIdeal(2, q, R, 'I')1087sage: IA1 is IA21088True1089"""1090if base_ring is None:1091base_ring = q.parent()1092return super(PropagatingIdeal, cls).__classcall__(cls, k, q, base_ring, prefix)10931094def __init__(self, k, q, base_ring, prefix):1095r"""1096Initialize ``self``.10971098TESTS::10991100sage: R.<q> = QQ[]1101sage: I = PropagatingIdeal(2, q, R)1102sage: TestSuite(I).run() # Not tested -- needs non-unital algebras category1103"""1104# This should be the category of non-unital fin-dim algebras with basis1105category = FiniteDimensionalAlgebrasWithBasis(base_ring)1106SubPartitionAlgebra.__init__(self, k, q, base_ring, prefix, ideal_diagrams, category)11071108@cached_method1109def one_basis(self):1110r"""1111The propagating ideal is a non-unital algebra, i.e. it does not have a1112multiplicative identity.11131114EXAMPLES::11151116sage: R.<q> = QQ[]1117sage: I = PropagatingIdeal(2, q, R)1118sage: I.one_basis()1119Traceback (most recent call last):1120...1121ValueError: The ideal partition algebra is not unital1122sage: I.one()1123Traceback (most recent call last):1124...1125ValueError: The ideal partition algebra is not unital1126"""1127raise ValueError("The ideal partition algebra is not unital")1128#return identity_set_partition(self._k)11291130def _repr_(self):1131"""1132Return a string representation of ``self``.11331134EXAMPLES::11351136sage: R.<x> = QQ[]1137sage: PropagatingIdeal(2, x, R)1138Propagating Ideal of rank 2 with parameter x over Univariate Polynomial Ring in x over Rational Field1139"""1140return "Propagating Ideal of rank %s with parameter %s over %s"%(self._k,1141self._q, self.base_ring())11421143class Element(SubPartitionAlgebra.Element):1144"""1145Need to take care of exponents since we are not unital.1146"""1147def __pow__(self, n):1148"""1149Return ``self`` to the `n`-th power.11501151INPUT::11521153- ``n`` -- a positive integer11541155EXAMPLES::11561157sage: R.<x> = QQ[]1158sage: I = PropagatingIdeal(2, x, R)1159sage: E = I([[1,2],[-1,-2]])1160sage: E^21161x*I[{{-2, -1}, {1, 2}}]1162sage: E^01163Traceback (most recent call last):1164...1165ValueError: can only take positive integer powers1166"""1167if n <= 0:1168raise ValueError("can only take positive integer powers")1169return generic_power(self, n)11701171#########################################################################1172# START BORROWED CODE1173#########################################################################1174# Borrowed from Mike Hansen's original code -- global methods for dealing1175# with partition diagrams, compositions of partition diagrams, and so on.1176# --> CHANGED 'identity' to 'identity_set_partition' for enhanced clarity.1177#########################################################################11781179def is_planar(sp):1180r"""1181Return ``True`` if the diagram corresponding to the set partition ``sp``1182is planar; otherwise, it return ``False``.11831184EXAMPLES::11851186sage: import sage.combinat.diagram_algebras as da1187sage: da.is_planar( da.to_set_partition([[1,-2],[2,-1]]))1188False1189sage: da.is_planar( da.to_set_partition([[1,-1],[2,-2]]))1190True1191"""1192to_consider = map(list, sp)11931194#Singletons don't affect planarity1195to_consider = filter(lambda x: len(x) > 1, to_consider)1196n = len(to_consider)11971198for i in range(n):1199#Get the positive and negative entries of this part1200ap = filter(lambda x: x>0, to_consider[i])1201an = filter(lambda x: x<0, to_consider[i])1202an = map(abs, an)12031204#Check if a includes numbers in both the top and bottom rows1205if len(ap) > 0 and len(an) > 0:1206for j in range(n):1207if i == j:1208continue1209#Get the positive and negative entries of this part1210bp = filter(lambda x: x>0, to_consider[j])1211bn = filter(lambda x: x<0, to_consider[j])1212bn = map(abs, bn)12131214#Skip the ones that don't involve numbers in both1215#the bottom and top rows1216if len(bn) == 0 or len(bp) == 0:1217continue12181219#Make sure that if min(bp) > max(ap)1220#then min(bn) > max(an)1221if max(bp) > max(ap):1222if min(bn) < min(an):1223return False12241225#Go through the bottom and top rows1226for row in [ap, an]:1227if len(row) > 1:1228row.sort()1229for s in range(len(row)-1):1230if row[s] + 1 == row[s+1]:1231#No gap, continue on1232continue12331234rng = range(row[s] + 1, row[s+1])12351236#Go through and make sure any parts that1237#contain numbers in this range are completely1238#contained in this range1239for j in range(n):1240if i == j:1241continue12421243#Make sure we make the numbers negative again1244#if we are in the bottom row1245if row is ap:1246sr = Set(rng)1247else:1248sr = Set(map(lambda x: -1*x, rng))12491250sj = Set(to_consider[j])1251intersection = sr.intersection(sj)1252if intersection:1253if sj != intersection:1254return False12551256return True125712581259def to_graph(sp):1260r"""1261Return a graph representing the set partition ``sp``.12621263EXAMPLES::12641265sage: import sage.combinat.diagram_algebras as da1266sage: g = da.to_graph( da.to_set_partition([[1,-2],[2,-1]])); g1267Graph on 4 vertices12681269sage: g.vertices()1270[-2, -1, 1, 2]1271sage: g.edges()1272[(-2, 1, None), (-1, 2, None)]1273"""1274g = Graph()1275for part in sp:1276part_list = list(part)1277if len(part_list) > 0:1278g.add_vertex(part_list[0])1279for i in range(1, len(part_list)):1280g.add_vertex(part_list[i])1281g.add_edge(part_list[i-1], part_list[i])1282return g12831284def pair_to_graph(sp1, sp2):1285r"""1286Return a graph consisting of the graphs of set partitions ``sp1`` and1287``sp2`` along with edges joining the bottom row (negative numbers) of1288``sp1`` to the top row (positive numbers) of ``sp2``.12891290EXAMPLES::12911292sage: import sage.combinat.diagram_algebras as da1293sage: sp1 = da.to_set_partition([[1,-2],[2,-1]])1294sage: sp2 = da.to_set_partition([[1,-2],[2,-1]])1295sage: g = da.pair_to_graph( sp1, sp2 ); g1296Graph on 8 vertices12971298sage: g.vertices()1299[(-2, 1), (-2, 2), (-1, 1), (-1, 2), (1, 1), (1, 2), (2, 1), (2, 2)]1300sage: g.edges()1301[((-2, 1), (1, 1), None), ((-2, 1), (2, 2), None),1302((-2, 2), (1, 2), None), ((-1, 1), (1, 2), None),1303((-1, 1), (2, 1), None), ((-1, 2), (2, 2), None)]1304"""1305g = Graph()13061307#Add the first set partition to the graph1308for part in sp1:1309part_list = list(part)1310if len(part_list) > 0:1311g.add_vertex( (part_list[0],1) )13121313#Add the edge to the second part of the graph1314if part_list[0] < 0 and len(part_list) > 1:1315g.add_edge( (part_list[0], 1), (abs(part_list[0]), 2) )13161317for i in range(1, len(part_list)):1318g.add_vertex( (part_list[i],1) )13191320#Add the edge to the second part of the graph1321if part_list[i] < 0:1322g.add_edge( (part_list[i], 1), (abs(part_list[i]),2) )13231324#Add the edge between parts1325g.add_edge( (part_list[i-1],1), (part_list[i],1) )13261327#Add the second set partition to the graph1328for part in sp2:1329part_list = list(part)1330if len(part_list) > 0:1331g.add_vertex( (part_list[0],2) )1332for i in range(1, len(part_list)):1333g.add_vertex( (part_list[i],2) )1334g.add_edge( (part_list[i-1],2), (part_list[i],2) )13351336return g13371338def propagating_number(sp):1339r"""1340Return the propagating number of the set partition ``sp``.13411342The propagating number is the number of blocks with both a positive and1343negative number.13441345EXAMPLES::13461347sage: import sage.combinat.diagram_algebras as da1348sage: sp1 = da.to_set_partition([[1,-2],[2,-1]])1349sage: sp2 = da.to_set_partition([[1,2],[-2,-1]])1350sage: da.propagating_number(sp1)135121352sage: da.propagating_number(sp2)135301354"""1355pn = 01356for part in sp:1357if min(part) < 0 and max(part) > 0:1358pn += 11359return pn13601361def to_set_partition(l, k=None):1362r"""1363Convert a list of a list of numbers to a set partitions. Each list1364of numbers in the outer list specifies the numbers contained in one1365of the blocks in the set partition.13661367If `k` is specified, then the set partition will be a set partition1368of `\{1, \ldots, k, -1, \ldots, -k\}`. Otherwise, `k` will default to1369the minimum number needed to contain all of the specified numbers.13701371EXAMPLES::13721373sage: import sage.combinat.diagram_algebras as da1374sage: da.to_set_partition([[1,-1],[2,-2]]) == da.identity_set_partition(2)1375True1376"""1377if k == None:1378if l == []:1379return SetPartition([])1380else:1381k = max( map( lambda x: max( map(abs, x) ), l) )13821383to_be_added = Set( range(1, k+1) + map(lambda x: -1*x, range(1, k+1) ) )13841385sp = []1386for part in l:1387spart = Set(part)1388to_be_added -= spart1389sp.append(spart)13901391for singleton in to_be_added:1392sp.append(Set([singleton]))13931394return SetPartition(sp)13951396def to_Brauer_partition(l, k=None):1397r"""1398Same as :func:`to_set_partition` but assumes omitted elements are1399connected straight through.14001401EXAMPLES::14021403sage: import sage.combinat.diagram_algebras as da1404sage: da.to_Brauer_partition([[1,2],[-1,-2]]) == SetPartition([[1,2],[-1,-2]])1405True1406sage: da.to_Brauer_partition([[1,3],[-1,-3]]) == SetPartition([[1,3],[-3,-1],[2,-2]])1407True1408sage: da.to_Brauer_partition([[1,2],[-1,-2]], k=4) == SetPartition([[1,2],[-1,-2],[3,-3],[4,-4]])1409True1410sage: da.to_Brauer_partition([[1,-4],[-3,-1],[3,4]]) == SetPartition([[-3,-1],[2,-2],[1,-4],[3,4]])1411True1412"""1413L = to_set_partition(l, k=k)1414L2 = []1415paired = []1416not_paired = []1417for i in L:1418L2.append(list(i))1419for i in L2:1420if len(i) >= 3:1421raise ValueError("blocks must have size at most 2, but {0} has {1}".format(i, len(i)))1422if (len(i) == 2):1423paired.append(i)1424if (len(i) == 1):1425not_paired.append(i)1426if any(i[0] in j or -1*i[0] in j for i in not_paired for j in paired):1427raise ValueError("unable to convert {0} to a Brauer partition due to the invalid block {1}".format(l, i))1428for i in not_paired:1429if [-1*i[0]] in not_paired:1430not_paired.remove([-1*i[0]])1431paired.append([i[0], -1*i[0]])1432return to_set_partition(paired)14331434def identity_set_partition(k):1435"""1436Return the identity set partition `\{\{1, -1\}, \ldots, \{k, -k\}\}`14371438EXAMPLES::14391440sage: import sage.combinat.diagram_algebras as da1441sage: da.identity_set_partition(2)1442{{-2, 2}, {-1, 1}}1443"""1444if k in ZZ:1445return SetPartition( [[i,-i] for i in range(1, k + 1)] )1446# Else k in 1/2 ZZ1447return SetPartition( [[i, -i] for i in range(1, k + ZZ(3)/ZZ(2))] )14481449def set_partition_composition(sp1, sp2):1450r"""1451Return a tuple consisting of the composition of the set partitions1452``sp1`` and ``sp2`` and the number of components removed from the middle1453rows of the graph.14541455EXAMPLES::14561457sage: import sage.combinat.diagram_algebras as da1458sage: sp1 = da.to_set_partition([[1,-2],[2,-1]])1459sage: sp2 = da.to_set_partition([[1,-2],[2,-1]])1460sage: da.set_partition_composition(sp1, sp2) == (da.identity_set_partition(2), 0)1461True1462"""1463g = pair_to_graph(sp1, sp2)1464connected_components = g.connected_components()14651466res = []1467total_removed = 01468for cc in connected_components:1469#Remove the vertices that live in the middle two rows1470new_cc = filter(lambda x: not ( (x[0]<0 and x[1] == 1) or (x[0]>0 and x[1]==2)), cc)14711472if new_cc == []:1473if len(cc) > 1:1474total_removed += 11475else:1476res.append( Set(map(lambda x: x[0], new_cc)) )14771478return (SetPartition(Set(res)), total_removed)14791480##########################################################################1481# END BORROWED CODE1482##########################################################################1483148414851486