| 1 | #from sage.combinat.permutation import Permutation_Class |
| 2 | from sage.structure.unique_representation import UniqueRepresentation |
| 3 | from sage.structure.parent import Parent |
| 4 | from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets |
| 5 | from sage.misc.classcall_metaclass import ClasscallMetaclass |
| 6 | from sage.structure.element_wrapper import ElementWrapper |
| 7 | from sage.structure.element import Element |
| 8 | from sage.misc.cachefunc import cached_method |
| 9 | from sage.rings.integer import Integer |
| 10 | |
| 11 | class PerfectMatching(ElementWrapper): |
| 12 | r""" |
| 13 | Class of perfect matching. |
| 14 | |
| 15 | An instance of the class can be created from a list of pairs or from a fixed point-free involution as follows:: |
| 16 | |
| 17 | sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]);m |
| 18 | PerfectMatching [('a', 'e'), ('b', 'c'), ('d', 'f')] |
| 19 | sage: n=PerfectMatching([3,8,1,7,6,5,4,2]);n |
| 20 | PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)] |
| 21 | sage: isinstance(m,PerfectMatching) |
| 22 | True |
| 23 | |
| 24 | The parent, which is the set of perfect matching of the ground set, is automaticly created:: |
| 25 | |
| 26 | sage: n.parent() |
| 27 | Set of perfect matchings of {1, 2, 3, 4, 5, 6, 7, 8} |
| 28 | |
| 29 | If the ground set is ordered, one can, for example, ask if the matching is non crossing:: |
| 30 | |
| 31 | sage: PerfectMatching([(1, 4), (2, 3), (5, 6)]).is_non_crossing() |
| 32 | True |
| 33 | """ |
| 34 | #the data structure of the element is a list (accessible via x.value) |
| 35 | wrapper_class = list |
| 36 | __lt__ = ElementWrapper._lt_by_value |
| 37 | #During the creation of the instance of the class, the function __classcall_private__ will be called instead of __init__ directly. |
| 38 | __metaclass__ = ClasscallMetaclass |
| 39 | |
| 40 | @staticmethod |
| 41 | def __classcall_private__(cls,p): |
| 42 | from sage.combinat.permutation import Permutation |
| 43 | from sage.misc.flatten import flatten |
| 44 | r""" |
| 45 | This function tries to recognize the input (it can be either a list or a tuple of pairs, or a fix-point free involution given as a list or as a permutation), constructs the parent (enumerated set of PerfectMatchings of the ground set) and calls the __init__ function to construct our object. |
| 46 | |
| 47 | EXAMPLES:: |
| 48 | |
| 49 | sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]);m |
| 50 | PerfectMatching [('a', 'e'), ('b', 'c'), ('d', 'f')] |
| 51 | sage: isinstance(m,PerfectMatching) |
| 52 | True |
| 53 | sage: n=PerfectMatching([3,8,1,7,6,5,4,2]);n |
| 54 | PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)] |
| 55 | sage: n.parent() |
| 56 | Set of perfect matchings of {1, 2, 3, 4, 5, 6, 7, 8} |
| 57 | sage: PerfectMatching([(1, 4), (2, 3), (5, 6)]).is_non_crossing() |
| 58 | True |
| 59 | |
| 60 | TESTS:: |
| 61 | |
| 62 | sage: TestSuite(m).run() |
| 63 | """ |
| 64 | #we have to extract from the argument p the set of objects of the matching and the list of pairs |
| 65 | #First case: p is a list (resp tuple) of lists (resp tuple). |
| 66 | if (isinstance(p,list) or isinstance(p,tuple)) and ( |
| 67 | all([isinstance(x,list) or isinstance(x,tuple) for x in p])): |
| 68 | objects=flatten(p) |
| 69 | data=(map(tuple,p)) |
| 70 | #Second case: p is a permutation or a list of integers, we have to check if it is a fix-point-free involution. |
| 71 | elif ((isinstance(p,list) and all(map(lambda x: (isinstance(x,Integer) or isinstance(x,int)),p ))) |
| 72 | or isinstance(p,sage.combinat.permutation.Permutation_class)): |
| 73 | p=Permutation(p) |
| 74 | n=len(p) |
| 75 | if not(p.cycle_type()==[2 for i in range(n//2)]): |
| 76 | raise ValueError, "The permutation p (= %s) is not a fix-point-free involution"%p |
| 77 | objects=range(1,n+1) |
| 78 | data=p.to_cycles() |
| 79 | #Third case: p is already a perfect matching |
| 80 | elif isinstance(p,PerfectMatching): |
| 81 | data=p.value |
| 82 | objects=flatten(data) |
| 83 | else: |
| 84 | raise ValueError, "cannot convert p (= %s) to a PerfectMatching"%p |
| 85 | #Finally, we create the parent and the element using the element class of the parent. Note: as this function is private, when we create an object via parent.element_class(...), __init__ is directly executed and we do not have an infinite loop. |
| 86 | parent=PerfectMatchings(objects) |
| 87 | return parent.element_class(data,parent) |
| 88 | |
| 89 | def __init__(self,data,parent): |
| 90 | r""" |
| 91 | see __classcall_private__? |
| 92 | """ |
| 93 | self.value=data |
| 94 | Element.__init__(self,parent=parent) |
| 95 | |
| 96 | def _repr_(self): |
| 97 | r""" |
| 98 | returns the name of the object |
| 99 | |
| 100 | EXAMPLES:: |
| 101 | |
| 102 | sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]);m |
| 103 | PerfectMatching [('a', 'e'), ('b', 'c'), ('d', 'f')] |
| 104 | sage: n=PerfectMatching([3,8,1,7,6,5,4,2]);n |
| 105 | PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)] |
| 106 | """ |
| 107 | return 'PerfectMatching %s'%self.value |
| 108 | |
| 109 | def __eq__(self,other): |
| 110 | from sage.sets.set import Set |
| 111 | r""" |
| 112 | Compares two perfect matchings |
| 113 | |
| 114 | EXAMPLES:: |
| 115 | |
| 116 | sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]) |
| 117 | sage: n=PerfectMatching([('c','b'),('d','f'),('e','a')]) |
| 118 | sage: n==m |
| 119 | True |
| 120 | sage: n==PerfectMatching([('a','b'),('d','f'),('e','c')]) |
| 121 | False |
| 122 | |
| 123 | """ |
| 124 | try: |
| 125 | if other.parent() <> self.parent(): |
| 126 | return False |
| 127 | except AttributeError: |
| 128 | return False |
| 129 | return Set(map(Set,self.value))==Set(map(Set,other.value)) |
| 130 | |
| 131 | def size(self): |
| 132 | r""" |
| 133 | returns the size of the perfect matching, i.e. the number of elements in the ground set. |
| 134 | |
| 135 | EXAMPLES:: |
| 136 | |
| 137 | sage: m=PerfectMatching([(-3, 1), (2, 4), (-2, 7)]); m.size() |
| 138 | 6 |
| 139 | """ |
| 140 | return 2*len(self.value) |
| 141 | |
| 142 | def partner(self,x): |
| 143 | r""" |
| 144 | Returns the element in the same pair than x in the mathching `self`. |
| 145 | |
| 146 | EXAMPLES:: |
| 147 | |
| 148 | sage: m=PerfectMatching([(-3, 1), (2, 4), (-2, 7)]); m.partner(4) |
| 149 | 2 |
| 150 | sage: n=PerfectMatching([('c','b'),('d','f'),('e','a')]); n.partner('c') |
| 151 | 'b' |
| 152 | """ |
| 153 | for i in range(self.size()): |
| 154 | if self.value[i][0]==x: |
| 155 | return self.value[i][1] |
| 156 | if self.value[i][1]==x: |
| 157 | return self.value[i][0] |
| 158 | raise ValueError,"%s in not an element of the %s"%(x,self) |
| 159 | |
| 160 | def loop_type(self,other=None): |
| 161 | from sage.combinat.permutation import Permutation |
| 162 | from sage.combinat.partition import Partition |
| 163 | r""" |
| 164 | input: |
| 165 | |
| 166 | two perfect matchings of the same set (if the second argument is empty, the fonction an_element is called on the parent of the first) |
| 167 | |
| 168 | output: |
| 169 | |
| 170 | if we draw the two perfect matchings simultaneously as edges of a graph, the graph obtained is a union of cycles of even lengths. The function returns the ordered list of the semi-length of these cycles (considered as a partition) |
| 171 | |
| 172 | EXAMPLES:: |
| 173 | |
| 174 | sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]) |
| 175 | sage: n=PerfectMatching([('a','b'),('d','f'),('e','c')]) |
| 176 | sage: m.loop_type(n) |
| 177 | [2, 1] |
| 178 | """ |
| 179 | if other is None: |
| 180 | other=self.parent().an_element() |
| 181 | elif self.parent() <> other.parent(): |
| 182 | raise ValueError,"%s is not a matching of the ground set of %s"%(other,self) |
| 183 | n=self.size() |
| 184 | A2N=dict([(self.parent()._objects[i],i+1) for i in range(n)]) |
| 185 | permself=Permutation(map(lambda x:tuple(map(lambda a:A2N[a],x)), |
| 186 | self.value)) |
| 187 | permother=Permutation(map(lambda x:tuple(map(lambda a:A2N[a],x)), |
| 188 | other.value)) |
| 189 | part=(permself*permother).cycle_type() |
| 190 | part_exp=part.to_exp() |
| 191 | l=[] |
| 192 | for i in range(max(part),0,-1): |
| 193 | for j in range(part_exp[i-1]//2): |
| 194 | l.append(i) |
| 195 | return Partition(l) |
| 196 | |
| 197 | def number_of_loops(self,other=None): |
| 198 | r""" |
| 199 | input: |
| 200 | |
| 201 | two perfect matchings of the same set (if the second argument is empty, the fonction an_element is called on the parent of the first) |
| 202 | |
| 203 | output: |
| 204 | |
| 205 | if we draw the two perfect matchings simultaneously as edges of a graph, the graph obtained is a union of cycles of even lengths. The function returns their numbers |
| 206 | |
| 207 | EXAMPLES:: |
| 208 | |
| 209 | sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]) |
| 210 | sage: n=PerfectMatching([('a','b'),('d','f'),('e','c')]) |
| 211 | sage: m.number_of_loops(n) |
| 212 | 2 |
| 213 | """ |
| 214 | return len(self.loop_type(other)) |
| 215 | |
| 216 | def crossings(self): |
| 217 | r""" |
| 218 | input: |
| 219 | |
| 220 | A perfect matching on an *totally ordered* ground set. |
| 221 | |
| 222 | output: |
| 223 | |
| 224 | We place the element of a ground set and draw the perfect matching by linking the elements of the same pair in the upper half-plane. This function returns the list of the pairs of crossing lines (as a line correspond to a pair, it returns a list of pairs of pairs). |
| 225 | |
| 226 | EXAMPLES:: |
| 227 | |
| 228 | sage: n=PerfectMatching([3,8,1,7,6,5,4,2]); n |
| 229 | PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)] |
| 230 | sage: n.crossings() |
| 231 | [((1, 3), (2, 8))] |
| 232 | """ |
| 233 | x=self.value[:] |
| 234 | if len(x)==0: |
| 235 | return [] |
| 236 | (i,j)=x.pop(0) |
| 237 | res=PerfectMatching(x).crossings() |
| 238 | for (a,b) in x: |
| 239 | if (i<a<j<b) or (i<b<j<a) or (j<a<i<b) or (j<b<i<a) or ( |
| 240 | a<i<b<j) or (a<j<b<i) or (b<i<a<j) or (b<j<a<i): |
| 241 | res.append(((i,j),(a,b))) |
| 242 | return res |
| 243 | |
| 244 | def number_of_crossings(self): |
| 245 | r""" |
| 246 | input: |
| 247 | |
| 248 | A perfect matching on an *totally ordered* ground set. |
| 249 | |
| 250 | output: |
| 251 | |
| 252 | We place the element of a ground set and draw the perfect matching by linking the elements of the same pair in the upper half-plane. This function returns the number the pairs of crossing lines. |
| 253 | |
| 254 | EXAMPLES:: |
| 255 | |
| 256 | sage: n=PerfectMatching([3,8,1,7,6,5,4,2]); n |
| 257 | PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)] |
| 258 | sage: n.number_of_crossings() |
| 259 | 1 |
| 260 | """ |
| 261 | x=self.value[:] |
| 262 | if len(x)==0: |
| 263 | return 0 |
| 264 | (i,j)=x.pop(0) |
| 265 | res=PerfectMatching(x).number_of_crossings() |
| 266 | for (a,b) in x: |
| 267 | if (i<a<j<b) or (i<b<j<a) or (j<a<i<b) or (j<b<i<a) or ( |
| 268 | a<i<b<j) or (a<j<b<i) or (b<i<a<j) or (b<j<a<i): |
| 269 | res+=1 |
| 270 | return res |
| 271 | |
| 272 | def is_non_crossing(self): |
| 273 | r""" |
| 274 | input: |
| 275 | |
| 276 | A perfect matching on an *totally ordered* ground set. |
| 277 | |
| 278 | output: |
| 279 | |
| 280 | We place the element of a ground set and draw the perfect matching by linking the elements of the same pair in the upper half-plane. This function returns True if the picture obtained this way has no crossings. |
| 281 | |
| 282 | EXAMPLES:: |
| 283 | |
| 284 | sage: n=PerfectMatching([3,8,1,7,6,5,4,2]); n |
| 285 | PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)] |
| 286 | sage: n.is_non_crossing() |
| 287 | False |
| 288 | sage: PerfectMatching([(1, 4), (2, 3), (5, 6)]).is_non_crossing() |
| 289 | True |
| 290 | """ |
| 291 | x=self.value[:] |
| 292 | if len(x)==0: |
| 293 | return True |
| 294 | (i,j)=x.pop(0) |
| 295 | for (a,b) in x: |
| 296 | if (i<a<j<b) or (i<b<j<a) or (j<a<i<b) or (j<b<i<a) or ( |
| 297 | a<i<b<j) or (a<j<b<i) or (b<i<a<j) or (b<j<a<i): |
| 298 | return False |
| 299 | return PerfectMatching(x).is_non_crossing() |
| 300 | |
| 301 | def Weingarten_function(self,other,N): |
| 302 | r""" |
| 303 | Returns the Weingarten function of two pairings. This function is the value of some integrals over the orhtogonal groups O_N. |
| 304 | |
| 305 | EXAMPLES:: |
| 306 | |
| 307 | sage: var('N') |
| 308 | N |
| 309 | sage: m=PerfectMatching([(1,3),(2,4)]) |
| 310 | sage: n=PerfectMatching([(1,2),(3,4)]) |
| 311 | sage: factor(m.Weingarten_function(n,N)) |
| 312 | -1/((N - 1)*(N + 2)*N) |
| 313 | """ |
| 314 | W=self.parent().Weingarten_matrix(N) |
| 315 | return W[self.rank()][other.rank()] |
| 316 | |
| 317 | class PerfectMatchings(UniqueRepresentation,Parent): |
| 318 | r""" |
| 319 | Class of perfect matchings of a ground set. At the creation, the set can be given as any iterable object. If the argument is an integer n, it will be transformed into [1 .. n]:: |
| 320 | |
| 321 | sage: M=PerfectMatchings(6);M |
| 322 | Set of perfect matchings of {1, 2, 3, 4, 5, 6} |
| 323 | sage: PerfectMatchings([-1, -3, 1, 2]) |
| 324 | Set of perfect matchings of {1, 2, -3, -1} |
| 325 | |
| 326 | One can ask for the list, the cardinality or an element of a set of perfect matching:: |
| 327 | |
| 328 | sage: PerfectMatchings(4).list() |
| 329 | [PerfectMatching [(4, 1), (3, 2)], PerfectMatching [(4, 2), (3, 1)], PerfectMatching [(4, 3), (2, 1)]] |
| 330 | sage: PerfectMatchings(8).cardinality() |
| 331 | 105 |
| 332 | sage: M=PerfectMatchings(('a', 'e', 'b', 'f', 'c', 'd')) |
| 333 | sage: M.an_element() |
| 334 | PerfectMatching [('a', 'e'), ('c', 'd'), ('b', 'f')] |
| 335 | sage: all([PerfectMatchings(i).an_element() in PerfectMatchings(i) for i in range(2,11,2)]) |
| 336 | True |
| 337 | """ |
| 338 | |
| 339 | @staticmethod |
| 340 | def _parse_input(objects): |
| 341 | from sage.sets.set import Set |
| 342 | r""" |
| 343 | This function tries to recognize the argument and to transform into a set. It is not meant to be called manually, but only as the first of the creation of an enumerated set of PerfectMatchings. |
| 344 | |
| 345 | EXAMPLES:: |
| 346 | |
| 347 | sage: PerfectMatchings._parse_input(4) |
| 348 | {1, 2, 3, 4} |
| 349 | sage: PerfectMatchings._parse_input(['a','b','c','e']) |
| 350 | {'a', 'c', 'b', 'e'} |
| 351 | """ |
| 352 | #if the argument is a python integer n, we replace it by the list [1 .. n] |
| 353 | if isinstance(objects,int): |
| 354 | objects=range(1,objects+1) |
| 355 | #same thing if the argument is a sage integer. |
| 356 | elif isinstance(objects,Integer): |
| 357 | objects=range(1,objects+1) |
| 358 | #Finally, if it is iterable, we return the corresponding set. Note that it is important to return a hashable object here (in particular, NOT A LIST), see comment below. |
| 359 | if not hasattr(objects,'__iter__'): |
| 360 | raise ValueError, "do not know how to construct a set of matchings from %s (it must be iterable)" |
| 361 | return Set(objects) |
| 362 | |
| 363 | @staticmethod |
| 364 | def __classcall__(cls, objects): |
| 365 | r""" |
| 366 | This function is called automatically when the user want to create an enumerated set of PerfectMatchings. |
| 367 | |
| 368 | EXAMPLES:: |
| 369 | |
| 370 | sage: M=PerfectMatchings(6);M |
| 371 | Set of perfect matchings of {1, 2, 3, 4, 5, 6} |
| 372 | sage: PerfectMatchings([-1, -3, 1, 2]) |
| 373 | Set of perfect matchings of {1, 2, -3, -1} |
| 374 | |
| 375 | If one has already created a set of perfect matchings of the same set, it does not create a new object, but returns the already existing one:: |
| 376 | |
| 377 | sage: N=PerfectMatchings((2, 3, 5, 4, 1, 6)) |
| 378 | sage: N is M |
| 379 | True |
| 380 | |
| 381 | The class constructor does not check that the perfect matching is correct, one has to use the function __contains__ for that:: |
| 382 | |
| 383 | sage: m=PerfectMatching([(1,2,3),(4,5)]) |
| 384 | sage: isinstance(m,PerfectMatching) |
| 385 | True |
| 386 | sage: m in m.parent() |
| 387 | False |
| 388 | |
| 389 | TEST:: |
| 390 | |
| 391 | sage: TestSuite(M).run() |
| 392 | """ |
| 393 | #we call the constructor of an other class, which will |
| 394 | # - check if the object has already been constructed (so the second argument, i.e. the output of _parse_input, must be hashable) |
| 395 | # - look for a place in memory and call the __init__ function |
| 396 | return super(PerfectMatchings, cls).__classcall__( |
| 397 | cls, cls._parse_input(objects)) |
| 398 | |
| 399 | def __init__(self,objects): |
| 400 | r""" |
| 401 | See __classcall__? |
| 402 | """ |
| 403 | self._objects=objects |
| 404 | Parent.__init__(self, category = FiniteEnumeratedSets()) |
| 405 | |
| 406 | def _repr_(self): |
| 407 | r""" |
| 408 | Returns a description of `self` |
| 409 | |
| 410 | EXAMPLES:: |
| 411 | |
| 412 | sage: PerfectMatchings([-1, -3, 1, 2]) |
| 413 | Set of perfect matchings of {1, 2, -3, -1} |
| 414 | """ |
| 415 | return "Set of perfect matchings of %s"%self._objects |
| 416 | |
| 417 | def __iter__(self): |
| 418 | r""" |
| 419 | Returns an iterator for the elements of self |
| 420 | |
| 421 | EXAMPLES:: |
| 422 | |
| 423 | sage: PerfectMatchings(4).list() |
| 424 | [PerfectMatching [(4, 1), (3, 2)], PerfectMatching [(4, 2), (3, 1)], PerfectMatching [(4, 3), (2, 1)]] |
| 425 | """ |
| 426 | if len(self._objects) == 0: |
| 427 | yield self([]) |
| 428 | elif len(self._objects) == 1: |
| 429 | pass |
| 430 | else: |
| 431 | l=list(self._objects) |
| 432 | a=l.pop(-1) |
| 433 | for i in range(len(l)): |
| 434 | obj_rest=l[:] |
| 435 | b=obj_rest.pop(i) |
| 436 | for p in PerfectMatchings(obj_rest): |
| 437 | yield self([(a,b)]+p.value) |
| 438 | |
| 439 | |
| 440 | def __contains__(self,x): |
| 441 | from sage.misc.flatten import flatten |
| 442 | from sage.combinat.permutation import Permutations |
| 443 | r""" |
| 444 | Tests if x is an element of self. |
| 445 | |
| 446 | EXAMPLES:: |
| 447 | |
| 448 | sage: m=PerfectMatching([(1,2),(4,3)]) |
| 449 | sage: m in PerfectMatchings(4) |
| 450 | True |
| 451 | sage: m in PerfectMatchings((0, 1, 2, 3)) |
| 452 | False |
| 453 | sage: all([m in PerfectMatchings(6) for m in PerfectMatchings(6)]) |
| 454 | True |
| 455 | |
| 456 | Note that the class of x does not need to be PerfectMatching: if the data defines a perfect matching of the good set, the function returns True:: |
| 457 | |
| 458 | sage: [(1, 4), (2, 3)] in PerfectMatchings(4) |
| 459 | True |
| 460 | |
| 461 | The class constructor does not check that the perfect matching is correct, one has to use the function __contains__ for that:: |
| 462 | |
| 463 | sage: m=PerfectMatching([(1,2,3),(4,5)]) |
| 464 | sage: isinstance(m,PerfectMatching) |
| 465 | True |
| 466 | sage: m in m.parent() |
| 467 | False |
| 468 | """ |
| 469 | if not isinstance(x,PerfectMatching): |
| 470 | try: |
| 471 | x=PerfectMatching(x) |
| 472 | except ValueError: |
| 473 | return False |
| 474 | if x.parent() is not self: |
| 475 | return False |
| 476 | A2N=dict([(self._objects[i],i+1) for i in range(len(self._objects))]) |
| 477 | if not all([len(i)==2 for i in x.value]): |
| 478 | return False |
| 479 | if map(lambda a:A2N[a],flatten(x.value)) not in Permutations(x.size()): |
| 480 | return False |
| 481 | return True |
| 482 | |
| 483 | def cardinality(self): |
| 484 | from sage.misc.misc_c import prod |
| 485 | r""" |
| 486 | Returns the cardinality of the set of perfect matching `self`, that is 1*3*5*...*(2n-1), where 2n is the size of the ground set. |
| 487 | |
| 488 | EXAMPLES:: |
| 489 | |
| 490 | sage: PerfectMatchings(8).cardinality() |
| 491 | 105 |
| 492 | """ |
| 493 | n=len(self._objects) |
| 494 | if n%2==1: |
| 495 | return 0 |
| 496 | else: |
| 497 | return prod(i for i in range(n) if i%2==1) |
| 498 | |
| 499 | def an_element(self): |
| 500 | r""" |
| 501 | Returns an element of self. |
| 502 | |
| 503 | EXAMPLES:: |
| 504 | |
| 505 | sage: M=PerfectMatchings(('a', 'e', 'b', 'f', 'c', 'd')) |
| 506 | sage: M.an_element() |
| 507 | PerfectMatching [('a', 'e'), ('c', 'd'), ('b', 'f')] |
| 508 | sage: all([PerfectMatchings(i).an_element() in PerfectMatchings(i) for i in range(2,11,2)]) |
| 509 | True |
| 510 | """ |
| 511 | n=len(self._objects)//2 |
| 512 | return PerfectMatching([(self._objects[i],self._objects[i+n]) for i in range(n)]) |
| 513 | |
| 514 | @cached_method |
| 515 | def Weingarten_matrix(self,N): |
| 516 | from sage.matrix.constructor import Matrix |
| 517 | r""" |
| 518 | Returns the Weingarten matrix corresponding to the set of PerfectMatchings `self`. It is a useful theoretical tool to compute polynomial integral over the orthogonal group O_N. |
| 519 | |
| 520 | EXAMPLES:: |
| 521 | |
| 522 | sage: M=PerfectMatchings(4).Weingarten_matrix(var('N')) |
| 523 | sage: N*(N-1)*(N+2)*M.apply_map(factor) |
| 524 | [N + 1 -1 -1] |
| 525 | [ -1 N + 1 -1] |
| 526 | [ -1 -1 N + 1] |
| 527 | """ |
| 528 | G=Matrix([ [N**(p1.number_of_loops(p2)) for p1 in self] |
| 529 | for p2 in self]) |
| 530 | return G**(-1) |
| 531 | |
| 532 | Element=PerfectMatching |
| 533 | |