Ticket #14234: trac_14232_latexDrawing.patch
File trac_14232_latexDrawing.patch, 36.1 KB (added by , 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 2 2 Diagram/Partition Algebras 3 3 """ 4 4 #***************************************************************************** 5 # Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>, 5 # Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>, 6 6 # 2012 Stephen Doty <doty@math.luc.edu>, 7 7 # Aaron Lauve <lauve@math.luc.edu>, 8 8 # George H. Seelinger <ghseeli@gmail.com> … … 12 12 #***************************************************************************** 13 13 from sage.categories.all import FiniteDimensionalAlgebrasWithBasis 14 14 from sage.combinat.family import Family 15 from sage.combinat.free_module import (CombinatorialFreeModule, 15 from sage.combinat.free_module import (CombinatorialFreeModule, 16 16 CombinatorialFreeModuleElement) 17 17 from sage.combinat.set_partition import SetPartitions 18 18 from sage.sets.set import Set 19 19 from sage.graphs.graph import Graph 20 20 from sage.misc.cachefunc import cached_method 21 from sage.misc.latex import latex 21 22 import collections 22 23 import functools, math 23 ##these four imports are for drawing diagrams; these may be removed in the final version.24 #import networkx25 #import pylab26 #import matplotlib.pyplot as plt27 #import itertools28 ##29 24 30 25 def partition_diagrams(k): 31 26 r""" … … 88 83 Set partitions of [1, 2, -1, -2] with sizes in [[2, 2]] 89 84 sage: brauer_diagrams(2.5) #random order 90 85 [{{1, 2}, {3, -3}, {-1, -2}}, {{2, -2}, {3, -3}, {1, -1}}, {{2, -1}, {3, -3}, {1, -2}}] 91 86 92 87 """ 93 88 if int(k) == k: 94 89 return SetPartitions( range(1,k+1) + [-j for j in range(1,k+1)], [2 for j in range(1,k+1)] ) … … 178 173 TODO: SHOULD BE MADE A METHOD OF THE SetPartitions CLASS ? 179 174 """ 180 175 return s in partition_diagrams(k) 181 182 class PartitionAlgebra(CombinatorialFreeModule): 176 177 class 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 339 class PartitionAlgebra(DiagramAlgebra): 183 340 r""" 184 341 INPUT: 185 342 … … 214 371 the product of two set partitions is simply given by their composition. 215 372 216 373 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. 218 375 219 376 An excellent reference for partition algebras and its various subalgebras 220 377 (Brauer algebra, Temperley-Lieb algebra, etc) is the paper [HR]_. … … 228 385 229 386 The following shorthand simultaneously define the univariate polynomial 230 387 ring over the rationals as well as the variable `x`:: 231 388 232 389 sage: R.<x> = PolynomialRing(QQ) 233 390 sage: R 234 391 Univariate Polynomial Ring in x over Rational Field … … 279 436 :: 280 437 281 438 sage: PA.one() #random order from SetPartitions 282 P[{{2, -2}, {1, -1}}] 439 P[{{2, -2}, {1, -1}}] 283 440 sage: PA.one()*P[7] 284 441 P[{{1, 2}, {-2, -1}}] 285 442 sage: P[7]*PA.one() … … 294 451 sage: PA = PartitionAlgebra(2, q, RR['q'], prefix='B') 295 452 sage: PA 296 453 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. 298 455 1.00000000000000*B[{{1, 2}, {-2, -1}}] 299 456 sage: PA = PartitionAlgebra(2, 5, base_ring=ZZ, prefix='B') 300 457 sage: PA 301 458 Partition Algebra of rank 2 with parameter 5 over Integer Ring, with prefix B 302 459 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? 304 461 16*B[{{1, 2}, {-2, -1}}] + B[{{2, -2}, {1, -1}}] 305 462 """ 306 463 … … 328 485 sage: PA = PartitionAlgebra(2, q, RR['q']) 329 486 sage: TestSuite(PA).run() 330 487 """ 331 332 488 self._k = k 333 489 self._prefix = prefix 334 490 self._q = base_ring(q) 335 491 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)) 338 493 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) 373 496 374 497 @cached_method 375 498 def one_basis(self): … … 405 528 """ 406 529 return self._k 407 530 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): 531 class BrauerAlgebra(DiagramAlgebra): 487 532 r""" 488 533 INPUT: 489 534 … … 505 550 506 551 The following shorthand simultaneously define the univariate polynomial 507 552 ring over the rationals as well as the variable `x`:: 508 553 509 554 sage: R.<x> = PolynomialRing(QQ) 510 555 sage: R 511 556 Univariate Polynomial Ring in x over Rational Field … … 555 600 self._prefix = prefix 556 601 self._q = base_ring(q) 557 602 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 560 605 @cached_method 561 606 def one_basis(self): 562 607 r""" … … 574 619 575 620 """ 576 621 return identity_set_partition(self._k) 577 622 578 623 def _repr_(self): 579 624 msg = "Brauer Algebra of rank %s with parameter %s over %s, with prefix %s" 580 625 return msg % (self._k, self._q, self.base_ring(), self._prefix) 581 626 582 627 def _element_constructor_(self, set_partition): 583 628 r""" 584 If BA is a particular Brauer algebra (previously defined) then 629 If BA is a particular Brauer algebra (previously defined) then 585 630 BA( sp ) returns the element of the algebra BA corresponding to a 586 631 given set partition sp. 587 632 … … 603 648 sage: BA([{1,2},{-1,-2}]) 604 649 B[{{1, 2}, {-1, -2}}] 605 650 """ 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 615 654 #These methods allow for BrauerAlgebra to be correctly identified as a sub-algebra of PartitionAlgebra 655 #With the DiagramAlgebra superclass, are these really necessary? 616 656 def ambient(self): 617 657 r""" 618 658 ambient returns the partition algebra the Brauer algebra is a sub-algebra of. … … 669 709 for i in xrange(len(monomial_coefficients)): 670 710 result += monomial_coefficients[i]*self.monomial(monomial_indices[i]) 671 711 return result 672 712 673 713 #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 using678 arithematic operators on elements.679 EXAMPLES::680 sage: BA = BrauerAlgebra(2, x)681 sage: E = BA([[1,2],[-1,-2]])682 sage: E*E683 x*B[{{1, 2}, {-2, -1}}]684 sage: E^4685 x^3*B[{{1, 2}, {-2, -1}}]686 """687 return self.ambient().product_on_basis(left,right)688 714 def order(self): 689 715 r""" 690 716 Returns the order of the Brauer Algebra … … 694 720 2 695 721 """ 696 722 return self.ambient().order() 697 698 class TemperleyLiebAlgebra( CombinatorialFreeModule):723 724 class TemperleyLiebAlgebra(DiagramAlgebra): 699 725 r""" 700 726 INPUT: 701 727 … … 717 743 718 744 The following shorthand simultaneously define the univariate polynomial 719 745 ring over the rationals as well as the variable `x`:: 720 746 721 747 sage: R.<x> = PolynomialRing(QQ); R 722 748 Univariate Polynomial Ring in x over Rational Field 723 749 sage: x … … 767 793 self._prefix = prefix 768 794 self._q = base_ring(q) 769 795 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)) 771 797 772 798 @cached_method 773 799 def one_basis(self): … … 816 842 sage: TL([{1,2},{-1,-2}]) 817 843 T[{{1, 2}, {-1, -2}}] 818 844 """ 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) 827 847 828 848 def ambient(self): 829 849 r""" … … 884 904 result += monomial_coefficients[i]*self.monomial(monomial_indices[i]) 885 905 return result 886 906 887 def product_on_basis(self, left, right):888 r"""889 This method is not made to be called directly but by using890 arithematic operators on elements.891 EXAMPLES::892 sage: TL = TemperleyLiebAlgebra(2, x)893 sage: E = TL([[1,2],[-1,-2]])894 sage: E*E895 x*T[{{1, 2}, {-2, -1}}]896 sage: E^4897 x^3*T[{{1, 2}, {-2, -1}}]898 """899 return self.ambient().product_on_basis(left,right)900 901 907 def order(self): 902 908 r""" 903 909 Returns the order of the Temperley-Lieb Algebra … … 908 914 """ 909 915 return self.ambient().order() 910 916 911 class PlanarAlgebra( CombinatorialFreeModule):917 class PlanarAlgebra(DiagramAlgebra): 912 918 r""" 913 919 INPUT: 914 920 … … 930 936 931 937 The following shorthand simultaneously define the univariate polynomial 932 938 ring over the rationals as well as the variable `x`:: 933 939 934 940 sage: R.<x> = PolynomialRing(QQ); R 935 941 Univariate Polynomial Ring in x over Rational Field 936 942 sage: x … … 980 986 self._prefix = prefix 981 987 self._q = base_ring(q) 982 988 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)) 984 990 985 991 @cached_method 986 992 def one_basis(self): … … 1005 1011 msg = "Planar Algebra of rank %s with parameter %s over %s, with prefix %s" 1006 1012 return msg % (self._k, self._q, self.base_ring(), self._prefix) 1007 1013 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 corresponding1012 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: PlA1019 Planar Algebra of rank 2 with parameter q over Univariate Polynomial Ring in q over Rational Field, with prefix Pl1020 sage: sp = to_set_partition( [[1,2], [-1,-2]] ) # create a set partition1021 sage: sp1022 {{1, 2}, {-1, -2}}1023 sage: PlA(sp) # construct a basis element from it1024 Pl[{{1, 2}, {-1, -2}}]1025 sage: PlA(sp) in PlA1026 True1027 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 coercion1036 assert sp in self.basis().keys() # did it work?1037 return self.monomial(sp)1038 else:1039 raise AssertionError, "%s invalid form" % set_partition1040 1041 1014 def ambient(self): 1042 1015 r""" 1043 1016 ambient returns the partition algebra the Planar algebra … … 1097 1070 result += monomial_coefficients[i]*self.monomial(monomial_indices[i]) 1098 1071 return result 1099 1072 1100 def product_on_basis(self, left, right):1101 r"""1102 This method is not made to be called directly but by using1103 arithematic operators on elements.1104 EXAMPLES::1105 sage: PlA = PlanarAlgebra(2, x)1106 sage: E = PlA([[1,2],[-1,-2]])1107 sage: E*E1108 x*Pl[{{1, 2}, {-2, -1}}]1109 sage: E^41110 x^3*Pl[{{1, 2}, {-2, -1}}]1111 """1112 return self.ambient().product_on_basis(left,right)1113 1114 1073 def order(self): 1115 1074 r""" 1116 1075 Returns the order of the Planar Algebra … … 1121 1080 """ 1122 1081 return self.ambient().order() 1123 1082 1124 class IdealAlgebra( CombinatorialFreeModule):1083 class IdealAlgebra(DiagramAlgebra): 1125 1084 r""" 1126 1085 INPUT: 1127 1086 … … 1143 1102 1144 1103 The following shorthand simultaneously define the univariate polynomial 1145 1104 ring over the rationals as well as the variable `x`:: 1146 1105 1147 1106 sage: R.<x> = PolynomialRing(QQ); R 1148 1107 Univariate Polynomial Ring in x over Rational Field 1149 1108 sage: x … … 1193 1152 self._prefix = prefix 1194 1153 self._q = base_ring(q) 1195 1154 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)) 1197 1156 1198 1157 @cached_method 1199 1158 def one_basis(self): … … 1203 1162 instead one should use I.one() if I is a 1204 1163 previously defined Ideal algebra instance. 1205 1164 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 1206 1170 TODO: 1207 1171 Make this method correct. 1208 1172 … … 1221 1185 msg = "Ideal Algebra of rank %s with parameter %s over %s, with prefix %s" 1222 1186 return msg % (self._k, self._q, self.base_ring(), self._prefix) 1223 1187 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 corresponding1228 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: I1235 Ideal Algebra of rank 2 with parameter q over Univariate Polynomial Ring in q over Rational Field, with prefix I1236 sage: sp = to_set_partition( [[1,2], [-1,-2]] ) # create a set partition1237 sage: sp1238 {{1, 2}, {-1, -2}}1239 sage: I(sp) # construct a basis element from it1240 I[{{1, 2}, {-1, -2}}]1241 sage: I(sp) in I1242 True1243 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 coercion1252 assert sp in self.basis().keys() # did it work?1253 return self.monomial(sp)1254 else:1255 raise AssertionError, "%s invalid form" % set_partition1256 1257 1188 def ambient(self): 1258 1189 r""" 1259 1190 ambient returns the partition algebra the Ideal algebra … … 1313 1244 result += monomial_coefficients[i]*self.monomial(monomial_indices[i]) 1314 1245 return result 1315 1246 1316 def product_on_basis(self, left, right):1317 r"""1318 This method is not made to be called directly but by using1319 arithematic operators on elements.1320 EXAMPLES::1321 sage: I = IdealAlgebra(2, x)1322 sage: E = I([[1,2],[-1,-2]])1323 sage: E*E1324 x*I[{{1, 2}, {-2, -1}}]1325 sage: E^41326 x^3*I[{{1, 2}, {-2, -1}}]1327 """1328 return self.ambient().product_on_basis(left,right)1329 1330 1247 def order(self): 1331 1248 r""" 1332 1249 Returns the order of the Temperley-Lieb Algebra … … 1344 1261 # with partition diagrams, compositions of partition diagrams, and so on. 1345 1262 # --> CHANGED 'identity' to 'identity_set_partition' for enhanced clarity. 1346 1263 ######################################################################### 1347 1264 1348 1265 def is_planar(sp): 1349 1266 r""" 1350 1267 Returns True if the diagram corresponding to the set partition is 1351 1268 planar; otherwise, it returns False. 1352 1269 1353 1270 EXAMPLES:: 1354 1271 1355 1272 sage: import sage.combinat.partition_algebra as pa 1356 1273 sage: pa.is_planar( pa.to_set_partition([[1,-2],[2,-1]])) 1357 1274 False … … 1363 1280 #Singletons don't affect planarity 1364 1281 to_consider = filter(lambda x: len(x) > 1, to_consider) 1365 1282 n = len(to_consider) 1366 1283 1367 1284 for i in range(n): 1368 1285 #Get the positive and negative entries of this 1369 1286 #part … … 1406 1323 continue 1407 1324 else: 1408 1325 rng = range(row[s] + 1, row[s+1]) 1409 1326 1410 1327 #Go through and make sure any parts that 1411 1328 #contain numbers in this range are completely 1412 1329 #contained in this range … … 1421 1338 else: 1422 1339 sr = Set(map(lambda x: -1*x, rng)) 1423 1340 1424 1341 1425 1342 sj = Set(to_consider[j]) 1426 1343 intersection = sr.intersection(sj) 1427 1344 if intersection: … … 1430 1347 1431 1348 return True 1432 1349 1433 1350 1434 1351 def to_graph(sp): 1435 1352 r""" 1436 1353 Returns a graph representing the set partition sp. 1437 1354 1438 1355 EXAMPLES:: 1439 1356 1440 1357 sage: import sage.combinat.partition_algebra as pa 1441 1358 sage: g = pa.to_graph( pa.to_set_partition([[1,-2],[2,-1]])); g 1442 1359 Graph on 4 vertices 1443 1360 1444 1361 :: 1445 1362 1446 1363 sage: g.vertices() #random 1447 1364 [1, 2, -2, -1] 1448 1365 sage: g.edges() #random … … 1463 1380 Returns a graph consisting of the graphs of set partitions sp1 and 1464 1381 sp2 along with edges joining the bottom row (negative numbers) of 1465 1382 sp1 to the top row (positive numbers) of sp2. 1466 1383 1467 1384 EXAMPLES:: 1468 1385 1469 1386 sage: import sage.combinat.partition_algebra as pa 1470 1387 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]]) 1472 1389 sage: g = pa.pair_to_graph( sp1, sp2 ); g 1473 1390 Graph on 8 vertices 1474 1391 1475 1392 :: 1476 1393 1477 1394 sage: g.vertices() #random 1478 1395 [(1, 2), (-1, 1), (-2, 2), (-1, 2), (-2, 1), (2, 1), (2, 2), (1, 1)] 1479 1396 sage: g.edges() #random … … 1495 1412 #Add the edge to the second part of the graph 1496 1413 if part_list[0] < 0 and len(part_list) > 1: 1497 1414 g.add_edge( (part_list[0], 1), (abs(part_list[0]),2) ) 1498 1415 1499 1416 for i in range(1, len(part_list)): 1500 1417 g.add_vertex( (part_list[i],1) ) 1501 1418 1502 1419 #Add the edge to the second part of the graph 1503 1420 if part_list[i] < 0: 1504 1421 g.add_edge( (part_list[i], 1), (abs(part_list[i]),2) ) … … 1514 1431 for i in range(1, len(part_list)): 1515 1432 g.add_vertex( (part_list[i],2) ) 1516 1433 g.add_edge( (part_list[i-1],2), (part_list[i],2) ) 1517 1434 1518 1435 return g 1519 1436 1520 1437 def propagating_number(sp): … … 1522 1439 Returns the propagating number of the set partition sp. The 1523 1440 propagating number is the number of blocks with both a positive and 1524 1441 negative number. 1525 1442 1526 1443 EXAMPLES:: 1527 1444 1528 1445 sage: import sage.combinat.partition_algebra as pa 1529 1446 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]]) 1531 1448 sage: pa.propagating_number(sp1) 1532 1449 2 1533 1450 sage: pa.propagating_number(sp2) … … 1544 1461 Converts a list of a list of numbers to a set partitions. Each list 1545 1462 of numbers in the outer list specifies the numbers contained in one 1546 1463 of the blocks in the set partition. 1547 1464 1548 1465 If k is specified, then the set partition will be a set partition 1549 1466 of 1, ..., k, -1, ..., -k. Otherwise, k will default to the minimum 1550 1467 number needed to contain all of the specified numbers. 1551 1468 1552 1469 EXAMPLES:: 1553 1554 sage: import sage.combinat.partition_algebra as pa 1470 1471 sage: import sage.combinat.partition_algebra as pa #TODO: change this 1555 1472 sage: pa.to_set_partition([[1,-1],[2,-2]]) == pa.identity(2) 1556 1473 True 1557 1474 """ … … 1562 1479 k = max( map( lambda x: max( map(abs, x) ), l) ) 1563 1480 1564 1481 to_be_added = Set( range(1, k+1) + map(lambda x: -1*x, range(1, k+1) ) ) 1565 1482 1566 1483 sp = [] 1567 1484 for part in l: 1568 1485 spart = Set(part) … … 1573 1490 sp.append(Set([singleton])) 1574 1491 1575 1492 return Set(sp) 1493 def 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) 1576 1530 1577 1531 def identity_set_partition(k): 1578 1532 """ 1579 1533 Returns the identity set partition 1, -1, ..., k, -k 1580 1534 1581 1535 EXAMPLES:: 1582 1536 1583 1537 sage: identity_set_partition(2) #random order 1584 1538 {{2, -2}, {1, -1}} 1585 1539 """ … … 1593 1547 Returns a tuple consisting of the composition of the set partitions 1594 1548 sp1 and sp2 and the number of components removed from the middle 1595 1549 rows of the graph. 1596 1550 1597 1551 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? 1600 1554 sage: sp1 = pa.to_set_partition([[1,-2],[2,-1]]) 1601 1555 sage: sp2 = pa.to_set_partition([[1,-2],[2,-1]]) 1602 1556 sage: pa.set_partition_composition(sp1, sp2) == (pa.identity(2), 0) … … 1622 1576 1623 1577 ########################################################################## 1624 1578 # END BORROWED CODE 1625 ########################################################################## 1579 ########################################################################## 1626 1580