Ticket #14234: trac_14232_latexDrawing.patch

File trac_14232_latexDrawing.patch, 36.1 KB (added by ghseeli, 8 years ago)
  • sage/combinat/diagram_algebras.py

    # HG changeset patch
    # User George H. Seelinger <ghseeli@gmail.com>
    # Date 1369881292 14400
    # Node ID 67701ca9d7127018110cd655267011f15e977ec1
    # Parent  50e0a52c20ecd4e5125a11d46d32d1f53ae9f896
    Trac #14232: Added abstract DiagramAlgebra class and added latex drawing.
    
    diff --git a/sage/combinat/diagram_algebras.py b/sage/combinat/diagram_algebras.py
    a b  
    22Diagram/Partition Algebras
    33"""
    44#*****************************************************************************
    5 #  Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>, 
     5#  Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>,
    66#                2012 Stephen Doty <doty@math.luc.edu>,
    77#                     Aaron Lauve <lauve@math.luc.edu>,
    88#                     George H. Seelinger <ghseeli@gmail.com>
     
    1212#*****************************************************************************
    1313from sage.categories.all import FiniteDimensionalAlgebrasWithBasis
    1414from sage.combinat.family import Family
    15 from sage.combinat.free_module import (CombinatorialFreeModule, 
     15from sage.combinat.free_module import (CombinatorialFreeModule,
    1616    CombinatorialFreeModuleElement)
    1717from sage.combinat.set_partition import SetPartitions
    1818from sage.sets.set import Set
    1919from sage.graphs.graph import Graph
    2020from sage.misc.cachefunc import cached_method
     21from sage.misc.latex import latex
    2122import collections
    2223import functools, math
    23 ##these four imports are for drawing diagrams; these may be removed in the final version.
    24 #import networkx
    25 #import pylab
    26 #import matplotlib.pyplot as plt
    27 #import itertools
    28 ##
    2924
    3025def partition_diagrams(k):
    3126    r"""
     
    8883        Set partitions of [1, 2, -1, -2] with sizes in [[2, 2]]
    8984        sage: brauer_diagrams(2.5) #random order
    9085        [{{1, 2}, {3, -3}, {-1, -2}}, {{2, -2}, {3, -3}, {1, -1}}, {{2, -1}, {3, -3}, {1, -2}}]
    91        
     86
    9287    """
    9388    if int(k) == k:
    9489        return SetPartitions( range(1,k+1) + [-j for j in range(1,k+1)], [2 for j in range(1,k+1)] )
     
    178173    TODO: SHOULD BE MADE A METHOD OF THE SetPartitions CLASS ?
    179174    """
    180175    return s in partition_diagrams(k)
    181        
    182 class PartitionAlgebra(CombinatorialFreeModule):
     176
     177class DiagramAlgebra(CombinatorialFreeModule):
     178    r"""
     179    Abstract class designed not to be used directly.
     180    If used directly, the class could create an algebra
     181    that is not actually an algebra.
     182
     183    TESTS::
     184
     185        sage: D = DiagramAlgebra(x, QQ[x], 'P', partition_diagrams(2))
     186        sage: D.basis()
     187        Lazy family (Term map from Set partitions of [1, 2, -1, -2] to Free module generated by Set partitions of [1, 2, -1, -2] over Univariate Polynomial Ring in x over Rational Field(i))_{i in Set partitions of [1, 2, -1, -2]}
     188
     189    """
     190    def __init__(self, q, base_ring, prefix, diagrams):
     191        r"""
     192        See :class:`DiagramAlgebra` for full documentation.
     193
     194        TESTS::
     195            sage: D = DiagramAlgebra(x, QQ[x], 'P', partition_diagrams(2))
     196        """
     197        self._prefix = prefix
     198        self._q = base_ring(q)
     199        category = FiniteDimensionalAlgebrasWithBasis(base_ring)
     200        CombinatorialFreeModule.__init__(self, base_ring, diagrams,
     201                    category = category, prefix=prefix)
     202
     203    def _element_constructor_(self, set_partition):
     204        r"""
     205        If D is a particular diagram algebra (previously defined) then
     206        D( sp ) returns the element of the algebra D corresponding to a
     207        given set partition sp.
     208
     209        TESTS::
     210
     211            sage: D = DiagramAlgebra(x, QQ[x], 'P', partition_diagrams(2))
     212            sage: sp = to_set_partition( [[1,2], [-1,-2]] )  # create a set partition
     213            sage: sp
     214            {{1, 2}, {-1, -2}}
     215            sage: D(sp)  # construct a basis element from it
     216            P[{{1, 2}, {-1, -2}}]
     217            sage: D(sp) in D
     218            True
     219            sage: D([[1,2],[-1,-2]])
     220            P[{{1, 2}, {-1, -2}}]
     221            sage: D([{1,2},{-1,-2}])
     222            P[{{1, 2}, {-1, -2}}]
     223        """
     224        if (set_partition in self.basis().keys()) and isinstance(set_partition, collections.Hashable):
     225            return self.monomial(set_partition)
     226        elif isinstance(set_partition, list):
     227            sp = to_set_partition(set_partition) # attempt coercion
     228            assert sp in self.basis().keys() # did it work?
     229            return self.monomial(sp)
     230        else:
     231            raise AssertionError, "%s invalid form" % set_partition
     232    def set_partitions(self):
     233        r"""
     234        This method returns the collection of underlying
     235        set partitions indexing the basis elements of a given
     236        diagram algebra.
     237
     238        TESTS::
     239            sage: D = DiagramAlgebra(x, QQ[x], 'P', partition_diagrams(2))
     240            sage: D.set_partitions() == partition_diagrams(2)
     241            True
     242        """
     243        return self.basis().keys()
     244
     245    def product_on_basis(self, d1, d2):
     246        r"""
     247        This method defines the product of two basis diagrams. Usually
     248        it is not called directly, but indirectly through usualy arithmetic
     249        operators.
     250
     251        TESTS::
     252            sage: D = DiagramAlgebra(x, QQ[x], 'P', partition_diagrams(2));
     253            sage: D.product_on_basis(D([[1,2],[-1,-2]]), D([[1,2],[-1,-2]]))
     254            x*P[{{1, {{1, 2}, {-1, -2}}}}]
     255        """
     256        (composite_diagram, loops_removed) = set_partition_composition(d1, d2)
     257        return self.term(composite_diagram, self._q**loops_removed)
     258    # The following subclass provides a few additional methods for
     259    # partition algebra elements.  NOTE: Most element methods we need are
     260    # ALREADY implemented! Use the __dir__() builtin python function
     261    # to figure out what methods are defined.
     262
     263    class Element(CombinatorialFreeModuleElement):
     264        r"""
     265        This subclass provides a few additional methods for
     266        partition algebra elements. Most element methods are
     267        already implemented elsewhere.
     268        """
     269
     270        def diagram(self):
     271            r"""
     272            This method returns the underlying diagram of a given
     273            basis element (or an error if not a basis element.)
     274            """
     275            if len(self) != 1:
     276                raise NotImplementedError("this works only for basis elements")
     277            PA = self.parent()
     278            ans = self.support_of_term()
     279            if is_partition_diagram(ans,PA.order()):
     280                return ans
     281            raise NotImplementedError("element should be keyed by a diagram")
     282
     283        def diagrams(self):
     284            r"""
     285            this method returns the diagrams in the support of any
     286            given element. It is just a rename of "support" which already exists.
     287            """
     288            return self.support()
     289        def _latex_(self):
     290            latex.add_to_mathjax_avoid_list('tikzpicture')
     291            latex.add_package_to_preamble_if_available('tikz') #these allow the view command to work. Should be moved?
     292            diagram = self.diagram()
     293            l1 = [] #list of blocks
     294            l2 = [] #lsit of nodes
     295            for i in list(diagram):
     296                l1.append(list(i))
     297                for j in list(i):
     298                    l2.append(j)
     299            output = "\\begin{tikzpicture}[scale = 0.9,thick] \n\\tikzstyle{vertex} = [shape = circle, minimum size = 9pt, inner sep = 1pt] \n" #setup beginning of picture
     300            for i in l2: #add nodes
     301                output = output + "\\node[vertex] (G-%s) at (%s, %s) [shape = circle, draw] {}; \n" % (i, (abs(i)-1)*1.5, sgn(i))
     302            for i in l1: #add edges
     303                if (len(i) > 1):
     304                    l4 = list(i)
     305                    posList = []
     306                    negList = []
     307                    for i in l4: #sort list so rows are grouped together
     308                        if i > 0:
     309                            posList.append(i)
     310                        elif i < 0:
     311                            negList.append(i)
     312                    posList.sort()
     313                    negList.sort()
     314                    l4 = posList + negList
     315                    l5 = l4[:] #deep copy
     316                    for j in range(len(l5)):
     317                        l5[j-1] = l4[j] #create a permuted list
     318                    if (len(l4) == 2):
     319                        l4.pop()
     320                        l5.pop() #pops to prevent duplicating edges
     321                    for j in zip(l4, l5):
     322                        xdiff = abs(j[1])-abs(j[0])
     323                        y1 = sgn(j[0])
     324                        y2 = sgn(j[1])
     325                        if ((y2-y1) == 0 and abs(xdiff) < 5): #if nodes are close to each other on same row
     326                            diffCo = (0.5+0.1*(abs(xdiff)-1)) #gets bigger as nodes are farther apart; max value of 1; min value of 0.5.
     327                            outVec = (sgn(xdiff)*diffCo, -1*diffCo*y1)
     328                            inVec = (-1*diffCo*sgn(xdiff), -1*diffCo*y2)
     329                        elif ((y2-y1) != 0 and abs(xdiff) == 1): #if nodes are close enough curviness looks bad.
     330                            outVec = (sgn(xdiff)*0.75, -1*y1)
     331                            inVec = (-1*sgn(xdiff)*0.75, -1*y2)
     332                        else:
     333                            outVec = (sgn(xdiff)*1, -1*y1)
     334                            inVec = (-1*sgn(xdiff), -1*y2)
     335                        output = output + "\\draw (G-%s) .. controls +%s and +%s .. (G-%s); \n" % (j[0], outVec, inVec,j[1])
     336            output = output + "\\end{tikzpicture}" #end picture
     337            return output
     338
     339class PartitionAlgebra(DiagramAlgebra):
    183340    r"""
    184341    INPUT:
    185342
     
    214371    the product of two set partitions is simply given by their composition.
    215372
    216373    The Iwahori-Hecke algebra of type A (with a single parameter) is naturally
    217     a subalgebra of the partition algebra. 
     374    a subalgebra of the partition algebra.
    218375
    219376    An excellent reference for partition algebras and its various subalgebras
    220377    (Brauer algebra, Temperley-Lieb algebra, etc) is the paper [HR]_.
     
    228385
    229386    The following shorthand simultaneously define the univariate polynomial
    230387    ring over the rationals as well as the variable `x`::
    231    
     388
    232389        sage: R.<x> = PolynomialRing(QQ)
    233390        sage: R
    234391        Univariate Polynomial Ring in x over Rational Field
     
    279436    ::
    280437
    281438        sage: PA.one() #random order from SetPartitions
    282         P[{{2, -2}, {1, -1}}] 
     439        P[{{2, -2}, {1, -1}}]
    283440        sage: PA.one()*P[7]
    284441        P[{{1, 2}, {-2, -1}}]
    285442        sage: P[7]*PA.one()
     
    294451        sage: PA = PartitionAlgebra(2, q, RR['q'], prefix='B')
    295452        sage: PA
    296453        Partition Algebra of rank 2 with parameter q over Univariate Polynomial Ring in q over Real Field with 53 bits of precision, with prefix B
    297         sage: PA.basis().list()[7]
     454        sage: PA([[1,2],[-1,-2]]) #random order due to set partitions.
    298455        1.00000000000000*B[{{1, 2}, {-2, -1}}]
    299456        sage: PA = PartitionAlgebra(2, 5, base_ring=ZZ, prefix='B')
    300457        sage: PA
    301458        Partition Algebra of rank 2 with parameter 5 over Integer Ring, with prefix B
    302459        sage: P = PA.basis().list()
    303         sage: (P[6] - 2*P[7])^2
     460        sage: (P[6] - 2*P[7])^2 #Is this an okay test? Is the order of basis elements always the same?
    304461        16*B[{{1, 2}, {-2, -1}}] + B[{{2, -2}, {1, -1}}]
    305462    """
    306463
     
    328485            sage: PA = PartitionAlgebra(2, q, RR['q'])
    329486            sage: TestSuite(PA).run()
    330487        """
    331 
    332488        self._k = k
    333489        self._prefix = prefix
    334490        self._q = base_ring(q)
    335491        category = FiniteDimensionalAlgebrasWithBasis(base_ring)
    336         CombinatorialFreeModule.__init__(self, base_ring, partition_diagrams(k),
    337                     category = category, prefix=prefix)
     492        DiagramAlgebra.__init__(self, q, base_ring, prefix, partition_diagrams(k))
    338493
    339     # The following constructs a basis element from a given set partition.
    340     # It should never be called directly.
    341     def _element_constructor_(self, set_partition):
    342         r"""
    343         If PA is a particular partition algebra (previously defined) then
    344         PA( sp ) returns the element of the algebra PA corresponding to a
    345         given set partition sp.
    346 
    347         EXAMPLES::
    348 
    349             sage: q = var('q')
    350             sage: PA = PartitionAlgebra(2,q,QQ['q'])
    351             sage: PA
    352             Partition Algebra of rank 2 with parameter q over Univariate Polynomial Ring in q over Rational Field, with prefix P
    353             sage: sp = to_set_partition( [[1,2], [-1,-2]] )  # create a set partition
    354             sage: sp
    355             {{1, 2}, {-1, -2}}
    356             sage: PA(sp)  # construct a basis element from it
    357             P[{{1, 2}, {-1, -2}}]
    358             sage: PA(sp) in PA
    359             True
    360             sage: PA([[1,2],[-1,-2]])
    361             P[{{1, 2}, {-1, -2}}]
    362             sage: PA([{1,2},{-1,-2}])
    363             P[{{1, 2}, {-1, -2}}]
    364         """
    365         if (set_partition in self.basis().keys()) and isinstance(set_partition, collections.Hashable):
    366             return self.monomial(set_partition)
    367         elif isinstance(set_partition, list):
    368             sp = to_set_partition(set_partition) # attempt coercion
    369             assert sp in self.basis().keys() # did it work?
    370             return self.monomial(sp)
    371         else:
    372             raise AssertionError, "%s invalid form" % set_partition
     494        #       CombinatorialFreeModule.__init__(self, base_ring, partition_diagrams(k),
     495        #            category = category, prefix=prefix)
    373496
    374497    @cached_method
    375498    def one_basis(self):
     
    405528        """
    406529        return self._k
    407530
    408     def set_partitions(self):
    409         r"""
    410         The method PA.set_partitions() returns the collection of underlying
    411         set partitions indexing the basis elements of the given partition
    412         algebra PA.
    413 
    414         EXAMPLES::
    415 
    416             sage: PA = PartitionAlgebra(2, x)
    417             sage: PA.set_partitions()
    418             Set partitions of [1, 2, -1, -2]
    419             sage: PA.set_partitions().list() #random order
    420             [{{1, 2, -1, -2}}, {{2, -1, -2}, {1}}, {{2}, {1, -1, -2}}, {{-1}, {1, 2, -2}}, {{-2}, {1, 2, -1}}, {{2, -1}, {1, -2}}, {{2, -2}, {1, -1}}, {{1, 2}, {-2, -1}}, {{2}, {-1, -2}, {1}}, {{-1}, {2, -2}, {1}}, {{-2}, {2, -1}, {1}}, {{-1}, {2}, {1, -2}}, {{-2}, {2}, {1, -1}}, {{-1}, {-2}, {1, 2}}, {{-1}, {-2}, {2}, {1}}]
    421         """
    422         return self.basis().keys()
    423    
    424     def product_on_basis(self, d1, d2):
    425         r"""
    426         This method defines the product of two basis diagrams. Usually
    427         it is not called directly, but indirectly through usualy arithmetic
    428         operators.
    429 
    430         TESTS::
    431             sage: P = PartitionAlgebra(2, x);
    432             sage: P.product_on_basis(P([[1,2],[-1,-2]]), P([[1,2],[-1,-2]]))
    433             x*P[{{1, {{1, 2}, {-1, -2}}}}]
    434         """
    435         (composite_diagram, loops_removed) = set_partition_composition(d1, d2)
    436         return self.term(composite_diagram, self._q**loops_removed)
    437 
    438 
    439     # The following subclass provides a few additional methods for
    440     # partition algebra elements.  NOTE: Most element methods we need are
    441     # ALREADY implemented! Use the __dir__() builtin python function
    442     # to figure out what methods are defined.
    443 
    444     class Element(CombinatorialFreeModuleElement):
    445         r"""
    446         This subclass provides a few additional methods for
    447         partition algebra elements. Most element methods are
    448         already implemented elsewhere.
    449         """
    450        
    451         def diagram(self):
    452             r"""
    453             This method returns the underlying diagram of a given
    454             basis element (or an error if not a basis element.)
    455             """
    456             if len(self) != 1:
    457                 raise NotImplementedError("this works only for basis elements")
    458             PA = self.parent()
    459             ans = self.support_of_term()
    460             if is_partition_diagram(ans,PA.order()):
    461                 return ans
    462             raise NotImplementedError("element should be keyed by a diagram")
    463 
    464         def diagrams(self):
    465             r"""
    466             this method returns the diagrams in the support of any
    467             given element. It is just a rename of "support" which already exists.
    468             """
    469             return self.support()
    470 #        def show(self):
    471 #            diagram = self.diagram()
    472 #            sp = to_set_partition(diagram)
    473 #            sageGraph = to_graph(sp)
    474 #            G = sageGraph.networkx_graph()
    475 #            flatlist = itertools.chain(*diagram)
    476 #            k = max(flatlist)
    477 #            pos=dict(zip(range(1,k+1),zip(range(1,k+1),[1]*k)))
    478 #            pos.update(dict(zip(reversed(range(-k,0)),zip(range(1,k+1),[0.5]*k))))
    479 #            plt.clf()
    480 #            networkx.draw(G,pos)
    481 #            pylab.xlim(-1,9)
    482 #            pylab.ylim(-1,2)
    483 #            plt.savefig("tmp.png", bbox_inches='tight', pad_inches=-1)
    484 #            plt.show()
    485 
    486 class BrauerAlgebra(CombinatorialFreeModule):
     531class BrauerAlgebra(DiagramAlgebra):
    487532    r"""
    488533    INPUT:
    489534
     
    505550
    506551    The following shorthand simultaneously define the univariate polynomial
    507552    ring over the rationals as well as the variable `x`::
    508    
     553
    509554        sage: R.<x> = PolynomialRing(QQ)
    510555        sage: R
    511556        Univariate Polynomial Ring in x over Rational Field
     
    555600        self._prefix = prefix
    556601        self._q = base_ring(q)
    557602        category = FiniteDimensionalAlgebrasWithBasis(base_ring)
    558         CombinatorialFreeModule.__init__(self, base_ring, brauer_diagrams(k), category = category, prefix=prefix)
    559    
     603        DiagramAlgebra.__init__(self, q, base_ring, prefix, brauer_diagrams(k))
     604
    560605    @cached_method
    561606    def one_basis(self):
    562607        r"""
     
    574619
    575620        """
    576621        return identity_set_partition(self._k)
    577    
     622
    578623    def _repr_(self):
    579624        msg = "Brauer Algebra of rank %s with parameter %s over %s, with prefix %s"
    580625        return msg % (self._k, self._q, self.base_ring(), self._prefix)
    581626
    582627    def _element_constructor_(self, set_partition):
    583628        r"""
    584         If BA is a particular Brauer algebra (previously defined) then 
     629        If BA is a particular Brauer algebra (previously defined) then
    585630        BA( sp ) returns the element of the algebra BA corresponding to a
    586631        given set partition sp.
    587632
     
    603648            sage: BA([{1,2},{-1,-2}])
    604649            B[{{1, 2}, {-1, -2}}]
    605650        """
    606         if (set_partition in self.basis().keys()) and isinstance(set_partition, collections.Hashable):
    607             return self.monomial(set_partition)
    608         elif isinstance(set_partition, list):
    609             sp = to_set_partition(set_partition) # attempt coercion
    610             assert sp in self.basis().keys() # did it work?
    611             return self.monomial(sp)
    612         else:
    613             raise AssertionError, "%s invalid form" % set_partition
    614    
     651        set_partition = to_Brauer_partition(set_partition, k = self.order())
     652        return DiagramAlgebra._element_constructor_(self, set_partition)
     653
    615654    #These methods allow for BrauerAlgebra to be correctly identified as a sub-algebra of PartitionAlgebra
     655    #With the DiagramAlgebra superclass, are these really necessary?
    616656    def ambient(self):
    617657        r"""
    618658        ambient returns the partition algebra the Brauer algebra is a sub-algebra of.
     
    669709        for i in xrange(len(monomial_coefficients)):
    670710            result += monomial_coefficients[i]*self.monomial(monomial_indices[i])
    671711        return result
    672    
     712
    673713    #These methods depend on the above three methods
    674    
    675     def product_on_basis(self, left, right):
    676         r"""
    677         This method is not made to be called directly but by using
    678         arithematic operators on elements.
    679         EXAMPLES::
    680             sage: BA = BrauerAlgebra(2, x)
    681             sage: E = BA([[1,2],[-1,-2]])
    682             sage: E*E
    683             x*B[{{1, 2}, {-2, -1}}]
    684             sage: E^4
    685             x^3*B[{{1, 2}, {-2, -1}}]
    686         """
    687         return self.ambient().product_on_basis(left,right)
    688714    def order(self):
    689715        r"""
    690716        Returns the order of the Brauer Algebra
     
    694720            2
    695721        """
    696722        return self.ambient().order()
    697    
    698 class TemperleyLiebAlgebra(CombinatorialFreeModule):
     723
     724class TemperleyLiebAlgebra(DiagramAlgebra):
    699725    r"""
    700726    INPUT:
    701727
     
    717743
    718744    The following shorthand simultaneously define the univariate polynomial
    719745    ring over the rationals as well as the variable `x`::
    720    
     746
    721747        sage: R.<x> = PolynomialRing(QQ); R
    722748        Univariate Polynomial Ring in x over Rational Field
    723749        sage: x
     
    767793        self._prefix = prefix
    768794        self._q = base_ring(q)
    769795        category = FiniteDimensionalAlgebrasWithBasis(base_ring)
    770         CombinatorialFreeModule.__init__(self, base_ring, temperley_lieb_diagrams(k), category = category, prefix=prefix)
     796        DiagramAlgebra.__init__(self, q, base_ring, prefix, temperley_lieb_diagrams(k))
    771797
    772798    @cached_method
    773799    def one_basis(self):
     
    816842            sage: TL([{1,2},{-1,-2}])
    817843            T[{{1, 2}, {-1, -2}}]
    818844        """
    819         if (set_partition in self.basis().keys()) and isinstance(set_partition, collections.Hashable):
    820             return self.monomial(set_partition)
    821         elif isinstance(set_partition, list):
    822             sp = to_set_partition(set_partition) # attempt coercion
    823             assert sp in self.basis().keys() # did it work?
    824             return self.monomial(sp)
    825         else:
    826             raise AssertionError, "%s invalid form" % set_partition
     845        set_partition = to_Brauer_partition(set_partition, k = self.order())
     846        return DiagramAlgebra._element_constructor_(self, set_partition)
    827847
    828848    def ambient(self):
    829849        r"""
     
    884904            result += monomial_coefficients[i]*self.monomial(monomial_indices[i])
    885905        return result
    886906
    887     def product_on_basis(self, left, right):
    888         r"""
    889         This method is not made to be called directly but by using
    890         arithematic operators on elements.
    891         EXAMPLES::
    892             sage: TL = TemperleyLiebAlgebra(2, x)
    893             sage: E = TL([[1,2],[-1,-2]])
    894             sage: E*E
    895             x*T[{{1, 2}, {-2, -1}}]
    896             sage: E^4
    897             x^3*T[{{1, 2}, {-2, -1}}]
    898         """
    899         return self.ambient().product_on_basis(left,right)
    900 
    901907    def order(self):
    902908        r"""
    903909        Returns the order of the Temperley-Lieb Algebra
     
    908914        """
    909915        return self.ambient().order()
    910916
    911 class PlanarAlgebra(CombinatorialFreeModule):
     917class PlanarAlgebra(DiagramAlgebra):
    912918    r"""
    913919    INPUT:
    914920
     
    930936
    931937    The following shorthand simultaneously define the univariate polynomial
    932938    ring over the rationals as well as the variable `x`::
    933    
     939
    934940        sage: R.<x> = PolynomialRing(QQ); R
    935941        Univariate Polynomial Ring in x over Rational Field
    936942        sage: x
     
    980986        self._prefix = prefix
    981987        self._q = base_ring(q)
    982988        category = FiniteDimensionalAlgebrasWithBasis(base_ring)
    983         CombinatorialFreeModule.__init__(self, base_ring, planar_diagrams(k), category = category, prefix=prefix)
     989        DiagramAlgebra.__init__(self, q, base_ring, prefix, planar_diagrams(k))
    984990
    985991    @cached_method
    986992    def one_basis(self):
     
    10051011        msg = "Planar Algebra of rank %s with parameter %s over %s, with prefix %s"
    10061012        return msg % (self._k, self._q, self.base_ring(), self._prefix)
    10071013
    1008     def _element_constructor_(self, set_partition):
    1009         r"""
    1010         If PlA is a particular Planar algebra (previously defined)
    1011         then PlA( sp ) returns the element of the algebra PlA corresponding
    1012         to a given set partition sp.
    1013 
    1014         EXAMPLES::
    1015 
    1016             sage: q = var('q')
    1017             sage: PlA = PlanarAlgebra(2,q,QQ['q'])
    1018             sage: PlA
    1019             Planar Algebra of rank 2 with parameter q over Univariate Polynomial Ring in q over Rational Field, with prefix Pl
    1020             sage: sp = to_set_partition( [[1,2], [-1,-2]] )  # create a set partition
    1021             sage: sp
    1022             {{1, 2}, {-1, -2}}
    1023             sage: PlA(sp)  # construct a basis element from it
    1024             Pl[{{1, 2}, {-1, -2}}]
    1025             sage: PlA(sp) in PlA
    1026             True
    1027             sage: PlA([[1,2],[-1,-2]])
    1028             Pl[{{1, 2}, {-1, -2}}]
    1029             sage: PlA([{1,2},{-1,-2}])
    1030             Pl[{{1, 2}, {-1, -2}}]
    1031         """
    1032         if (set_partition in self.basis().keys()) and isinstance(set_partition, collections.Hashable):
    1033             return self.monomial(set_partition)
    1034         elif isinstance(set_partition, list):
    1035             sp = to_set_partition(set_partition) # attempt coercion
    1036             assert sp in self.basis().keys() # did it work?
    1037             return self.monomial(sp)
    1038         else:
    1039             raise AssertionError, "%s invalid form" % set_partition
    1040 
    10411014    def ambient(self):
    10421015        r"""
    10431016        ambient returns the partition algebra the Planar algebra
     
    10971070            result += monomial_coefficients[i]*self.monomial(monomial_indices[i])
    10981071        return result
    10991072
    1100     def product_on_basis(self, left, right):
    1101         r"""
    1102         This method is not made to be called directly but by using
    1103         arithematic operators on elements.
    1104         EXAMPLES::
    1105             sage: PlA = PlanarAlgebra(2, x)
    1106             sage: E = PlA([[1,2],[-1,-2]])
    1107             sage: E*E
    1108             x*Pl[{{1, 2}, {-2, -1}}]
    1109             sage: E^4
    1110             x^3*Pl[{{1, 2}, {-2, -1}}]
    1111         """
    1112         return self.ambient().product_on_basis(left,right)
    1113 
    11141073    def order(self):
    11151074        r"""
    11161075        Returns the order of the Planar Algebra
     
    11211080        """
    11221081        return self.ambient().order()
    11231082
    1124 class IdealAlgebra(CombinatorialFreeModule):
     1083class IdealAlgebra(DiagramAlgebra):
    11251084    r"""
    11261085    INPUT:
    11271086
     
    11431102
    11441103    The following shorthand simultaneously define the univariate polynomial
    11451104    ring over the rationals as well as the variable `x`::
    1146    
     1105
    11471106        sage: R.<x> = PolynomialRing(QQ); R
    11481107        Univariate Polynomial Ring in x over Rational Field
    11491108        sage: x
     
    11931152        self._prefix = prefix
    11941153        self._q = base_ring(q)
    11951154        category = FiniteDimensionalAlgebrasWithBasis(base_ring)
    1196         CombinatorialFreeModule.__init__(self, base_ring, ideal_diagrams(k), category = category, prefix=prefix)
     1155        DiagramAlgebra.__init__(self, q, base_ring, prefix, ideal_diagrams(k))
    11971156
    11981157    @cached_method
    11991158    def one_basis(self):
     
    12031162        instead one should use I.one() if I is a
    12041163        previously defined Ideal algebra instance.
    12051164
     1165        Technically speaking, the Ideal algebra is an algebra
     1166        without a multiplicative identity. This has to be fixed
     1167        by the creation of a new category, such as
     1168        FiniteDimensionalAlgebraWithBasisWithoutUnity.
     1169
    12061170        TODO:
    12071171        Make this method correct.
    12081172
     
    12211185        msg = "Ideal Algebra of rank %s with parameter %s over %s, with prefix %s"
    12221186        return msg % (self._k, self._q, self.base_ring(), self._prefix)
    12231187
    1224     def _element_constructor_(self, set_partition):
    1225         r"""
    1226         If I is a particular Ideal algebra (previously defined)
    1227         then I( sp ) returns the element of the algebra I corresponding
    1228         to a given set partition sp.
    1229 
    1230         EXAMPLES::
    1231 
    1232             sage: q = var('q')
    1233             sage: I = IdealAlgebra(2,q,QQ['q'])
    1234             sage: I
    1235             Ideal Algebra of rank 2 with parameter q over Univariate Polynomial Ring in q over Rational Field, with prefix I
    1236             sage: sp = to_set_partition( [[1,2], [-1,-2]] )  # create a set partition
    1237             sage: sp
    1238             {{1, 2}, {-1, -2}}
    1239             sage: I(sp)  # construct a basis element from it
    1240             I[{{1, 2}, {-1, -2}}]
    1241             sage: I(sp) in I
    1242             True
    1243             sage: I([[1,2],[-1,-2]])
    1244             I[{{1, 2}, {-1, -2}}]
    1245             sage: I([{1,2},{-1,-2}])
    1246             I[{{1, 2}, {-1, -2}}]
    1247         """
    1248         if (set_partition in self.basis().keys()) and isinstance(set_partition, collections.Hashable):
    1249             return self.monomial(set_partition)
    1250         elif isinstance(set_partition, list):
    1251             sp = to_set_partition(set_partition) # attempt coercion
    1252             assert sp in self.basis().keys() # did it work?
    1253             return self.monomial(sp)
    1254         else:
    1255             raise AssertionError, "%s invalid form" % set_partition
    1256 
    12571188    def ambient(self):
    12581189        r"""
    12591190        ambient returns the partition algebra the Ideal algebra
     
    13131244            result += monomial_coefficients[i]*self.monomial(monomial_indices[i])
    13141245        return result
    13151246
    1316     def product_on_basis(self, left, right):
    1317         r"""
    1318         This method is not made to be called directly but by using
    1319         arithematic operators on elements.
    1320         EXAMPLES::
    1321             sage: I = IdealAlgebra(2, x)
    1322             sage: E = I([[1,2],[-1,-2]])
    1323             sage: E*E
    1324             x*I[{{1, 2}, {-2, -1}}]
    1325             sage: E^4
    1326             x^3*I[{{1, 2}, {-2, -1}}]
    1327         """
    1328         return self.ambient().product_on_basis(left,right)
    1329 
    13301247    def order(self):
    13311248        r"""
    13321249        Returns the order of the Temperley-Lieb Algebra
     
    13441261# with partition diagrams, compositions of partition diagrams, and so on.
    13451262# --> CHANGED 'identity' to 'identity_set_partition' for enhanced clarity.
    13461263#########################################################################
    1347                
     1264
    13481265def is_planar(sp):
    13491266    r"""
    13501267    Returns True if the diagram corresponding to the set partition is
    13511268    planar; otherwise, it returns False.
    1352    
     1269
    13531270    EXAMPLES::
    1354    
     1271
    13551272        sage: import sage.combinat.partition_algebra as pa
    13561273        sage: pa.is_planar( pa.to_set_partition([[1,-2],[2,-1]]))
    13571274        False
     
    13631280    #Singletons don't affect planarity
    13641281    to_consider = filter(lambda x: len(x) > 1, to_consider)
    13651282    n = len(to_consider)
    1366    
     1283
    13671284    for i in range(n):
    13681285        #Get the positive and negative entries of this
    13691286        #part
     
    14061323                        continue
    14071324                    else:
    14081325                        rng = range(row[s] + 1, row[s+1])
    1409                        
     1326
    14101327                        #Go through and make sure any parts that
    14111328                        #contain numbers in this range are completely
    14121329                        #contained in this range
     
    14211338                            else:
    14221339                                sr = Set(map(lambda x: -1*x, rng))
    14231340
    1424                            
     1341
    14251342                            sj = Set(to_consider[j])
    14261343                            intersection = sr.intersection(sj)
    14271344                            if intersection:
     
    14301347
    14311348    return True
    14321349
    1433    
     1350
    14341351def to_graph(sp):
    14351352    r"""
    14361353    Returns a graph representing the set partition sp.
    1437    
     1354
    14381355    EXAMPLES::
    1439    
     1356
    14401357        sage: import sage.combinat.partition_algebra as pa
    14411358        sage: g = pa.to_graph( pa.to_set_partition([[1,-2],[2,-1]])); g
    14421359        Graph on 4 vertices
    1443    
     1360
    14441361    ::
    1445    
     1362
    14461363        sage: g.vertices() #random
    14471364        [1, 2, -2, -1]
    14481365        sage: g.edges() #random
     
    14631380    Returns a graph consisting of the graphs of set partitions sp1 and
    14641381    sp2 along with edges joining the bottom row (negative numbers) of
    14651382    sp1 to the top row (positive numbers) of sp2.
    1466    
     1383
    14671384    EXAMPLES::
    1468    
     1385
    14691386        sage: import sage.combinat.partition_algebra as pa
    14701387        sage: sp1 = pa.to_set_partition([[1,-2],[2,-1]])
    1471         sage: sp2 = pa.to_set_partition([[1,-2],[2,-1]])       
     1388        sage: sp2 = pa.to_set_partition([[1,-2],[2,-1]])
    14721389        sage: g = pa.pair_to_graph( sp1, sp2 ); g
    14731390        Graph on 8 vertices
    1474    
     1391
    14751392    ::
    1476    
     1393
    14771394        sage: g.vertices() #random
    14781395        [(1, 2), (-1, 1), (-2, 2), (-1, 2), (-2, 1), (2, 1), (2, 2), (1, 1)]
    14791396        sage: g.edges() #random
     
    14951412            #Add the edge to the second part of the graph
    14961413            if part_list[0] < 0 and len(part_list) > 1:
    14971414                g.add_edge( (part_list[0], 1), (abs(part_list[0]),2)  )
    1498            
     1415
    14991416        for i in range(1, len(part_list)):
    15001417            g.add_vertex( (part_list[i],1) )
    1501            
     1418
    15021419            #Add the edge to the second part of the graph
    15031420            if part_list[i] < 0:
    15041421                g.add_edge( (part_list[i], 1), (abs(part_list[i]),2) )
     
    15141431        for i in range(1, len(part_list)):
    15151432            g.add_vertex( (part_list[i],2) )
    15161433            g.add_edge( (part_list[i-1],2), (part_list[i],2) )
    1517            
     1434
    15181435    return g
    15191436
    15201437def propagating_number(sp):
     
    15221439    Returns the propagating number of the set partition sp. The
    15231440    propagating number is the number of blocks with both a positive and
    15241441    negative number.
    1525    
     1442
    15261443    EXAMPLES::
    1527    
     1444
    15281445        sage: import sage.combinat.partition_algebra as pa
    15291446        sage: sp1 = pa.to_set_partition([[1,-2],[2,-1]])
    1530         sage: sp2 = pa.to_set_partition([[1,2],[-2,-1]])       
     1447        sage: sp2 = pa.to_set_partition([[1,2],[-2,-1]])
    15311448        sage: pa.propagating_number(sp1)
    15321449        2
    15331450        sage: pa.propagating_number(sp2)
     
    15441461    Converts a list of a list of numbers to a set partitions. Each list
    15451462    of numbers in the outer list specifies the numbers contained in one
    15461463    of the blocks in the set partition.
    1547    
     1464
    15481465    If k is specified, then the set partition will be a set partition
    15491466    of 1, ..., k, -1, ..., -k. Otherwise, k will default to the minimum
    15501467    number needed to contain all of the specified numbers.
    1551    
     1468
    15521469    EXAMPLES::
    1553    
    1554         sage: import sage.combinat.partition_algebra as pa
     1470
     1471        sage: import sage.combinat.partition_algebra as pa #TODO: change this
    15551472        sage: pa.to_set_partition([[1,-1],[2,-2]]) == pa.identity(2)
    15561473        True
    15571474    """
     
    15621479            k = max( map( lambda x: max( map(abs, x) ), l) )
    15631480
    15641481    to_be_added = Set( range(1, k+1) + map(lambda x: -1*x, range(1, k+1) ) )
    1565    
     1482
    15661483    sp = []
    15671484    for part in l:
    15681485        spart = Set(part)
     
    15731490        sp.append(Set([singleton]))
    15741491
    15751492    return Set(sp)
     1493def to_Brauer_partition(l,k=None):
     1494    r"""
     1495    Works like to_set_partition but assumes ommitted elements are
     1496    connected straight through.
     1497
     1498    EXAMPLES::
     1499
     1500        sage: to_Brauer_partition([[1,2],[-1,-2]])
     1501        {{1, 2}, {-1, -2}}
     1502        sage: to_Brauer_partition([[1,3],[-1,-3]])
     1503        {{1, 3}, {-3, -1}, {2, -2}}
     1504        sage: to_Brauer_partition([[1,2],[-1,-2]], k=4)
     1505        {{1, 2}, {3, -3}, {-1, -2}, {4, -4}}
     1506        sage: to_Brauer_partition([[1,-4],[-3,-1],[3,4]])
     1507        {{-3, -1}, {2, -2}, {1, -4}, {3, 4}}
     1508    """
     1509    L = to_set_partition(l, k)
     1510    L2 = []
     1511    paired = []
     1512    not_paired = []
     1513    for i in L:
     1514        L2.append(list(i))
     1515    for i in L2:
     1516        assert len(i) < 3
     1517        if (len(i) == 2):
     1518            paired.append(i)
     1519        if (len(i) == 1):
     1520            not_paired.append(i)
     1521    for i in not_paired:
     1522        for j in paired:
     1523            assert i[0] not in j
     1524            assert -1*i[0] not in j
     1525    for i in not_paired:
     1526        if [-1*i[0]] in not_paired:
     1527            not_paired.remove([-1*i[0]])
     1528        paired.append([i[0], -1*i[0]])
     1529    return to_set_partition(paired)
    15761530
    15771531def identity_set_partition(k):
    15781532    """
    15791533    Returns the identity set partition 1, -1, ..., k, -k
    1580    
     1534
    15811535    EXAMPLES::
    1582    
     1536
    15831537        sage: identity_set_partition(2) #random order
    15841538        {{2, -2}, {1, -1}}
    15851539    """
     
    15931547    Returns a tuple consisting of the composition of the set partitions
    15941548    sp1 and sp2 and the number of components removed from the middle
    15951549    rows of the graph.
    1596    
     1550
    15971551    EXAMPLES::
    1598    
    1599         sage: import sage.combinat.partition_algebra as pa
     1552
     1553        sage: import sage.combinat.partition_algebra as pa #change to this file?
    16001554        sage: sp1 = pa.to_set_partition([[1,-2],[2,-1]])
    16011555        sage: sp2 = pa.to_set_partition([[1,-2],[2,-1]])
    16021556        sage: pa.set_partition_composition(sp1, sp2) == (pa.identity(2), 0)
     
    16221576
    16231577##########################################################################
    16241578# END BORROWED CODE
    1625 ##########################################################################   
     1579##########################################################################
    16261580