# Ticket #9890: trac_9890_review.patch

File trac_9890_review.patch, 32.5 KB (added by chapoton, 7 years ago)
• ## sage/combinat/perfect_matching.py

```# HG changeset patch
# User Frederic Chapoton <chapoton at math.univ-lyon1.fr>
# Date 1368819378 -7200
# Node ID e1bd7bedc6784d47392b50195e80b43486ffa634
# Parent  8708a5383e0f4e1130a037a7389118dd9c74e3fa
trac #9890 review and remove <>

diff --git a/sage/combinat/perfect_matching.py b/sage/combinat/perfect_matching.py```
 a EXAMPLES: Create a perfect matching:: sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]);m sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')]);m [('a', 'e'), ('b', 'c'), ('d', 'f')] Count its crossings, if the ground set is totally ordered:: sage: n=PerfectMatching([3,8,1,7,6,5,4,2]); n sage: n = PerfectMatching([3,8,1,7,6,5,4,2]); n [(1, 3), (2, 8), (4, 7), (5, 6)] sage: n.number_of_crossings() 1 REFERENCES: VII). .. [CM] Benoit Collins, Sho Matsumoto, On some properties of orthogonal Weingarten functions, arXiv:0903.5143. orthogonal Weingarten functions, :arxiv:`0903.5143`. """ #***************************************************************************** #***************************************************************************** #       Copyright (C) 2010 Valentin Feray # #  Distributed under the terms of the GNU General Public License (GPL) from sage.misc.misc_c import prod from sage.matrix.constructor import Matrix from sage.combinat.combinatorial_map import combinatorial_map class PerfectMatching(ElementWrapper): r""" Class of perfect matching. class PerfectMatching(ElementWrapper): An instance of the class can be created from a list of pairs or from a fixed point-free involution as follows:: sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]);m sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')]);m [('a', 'e'), ('b', 'c'), ('d', 'f')] sage: n=PerfectMatching([3,8,1,7,6,5,4,2]);n sage: n = PerfectMatching([3,8,1,7,6,5,4,2]);n [(1, 3), (2, 8), (4, 7), (5, 6)] sage: isinstance(m,PerfectMatching) True The parent, which is the set of perfect matching of the ground set, is automaticly created:: The parent, which is the set of perfect matchings of the ground set, is automatically created:: sage: n.parent() Set of perfect matchings of {1, 2, 3, 4, 5, 6, 7, 8} class PerfectMatching(ElementWrapper): TESTS:: sage: m=PerfectMatching([]); m sage: m = PerfectMatching([]); m [] sage: m.parent() Set of perfect matchings of {} class PerfectMatching(ElementWrapper): __metaclass__ = ClasscallMetaclass @staticmethod def __classcall_private__(cls,p): def __classcall_private__(cls, p): r""" 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 class PerfectMatching(ElementWrapper): EXAMPLES:: sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]);m sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')]);m [('a', 'e'), ('b', 'c'), ('d', 'f')] sage: isinstance(m,PerfectMatching) True sage: n=PerfectMatching([3, 8, 1, 7, 6, 5, 4, 2]);n sage: n = PerfectMatching([3, 8, 1, 7, 6, 5, 4, 2]);n [(1, 3), (2, 8), (4, 7), (5, 6)] sage: n.parent() Set of perfect matchings of {1, 2, 3, 4, 5, 6, 7, 8} class PerfectMatching(ElementWrapper): TESTS:: sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]) sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')]) sage: TestSuite(m).run() sage: m=PerfectMatching([]) sage: m = PerfectMatching([]) sage: TestSuite(m).run() sage: PerfectMatching(6) Traceback (most recent call last): class PerfectMatching(ElementWrapper): # we have to extract from the argument p the set of objects of the # matching and the list of pairs. # First case: p is a list (resp tuple) of lists (resp tuple). if (isinstance(p,list) or isinstance(p,tuple)) and ( all([isinstance(x,list) or isinstance(x,tuple) for x in p])): objects=Set(flatten(p)) data=(map(tuple,p)) if (isinstance(p, list) or isinstance(p, tuple)) and ( all([isinstance(x, list) or isinstance(x, tuple) for x in p])): objects = Set(flatten(p)) data = (map(tuple, p)) #check if the data are correct if not all([len(t)==2 for t in data]): raise ValueError, ("%s is not a valid perfect matching:\n" "all elements of the list must be pairs"%p) if not all([len(t) == 2 for t in data]): raise ValueError("%s is not a valid perfect matching:\n" "all elements of the list must be pairs" % p) if len(objects) < 2*len(data): raise ValueError, ("%s is not a valid perfect matching:\n" "there are some repetitions"%p) raise ValueError("%s is not a valid perfect matching:\n" "there are some repetitions" % p) # Second case: p is a permutation or a list of integers, we have to # check if it is a fix-point-free involution. elif ((isinstance(p,list) and all(map(lambda x: (isinstance(x,Integer) or isinstance(x,int)),p ))) or isinstance(p,Permutation_class)): p=Permutation(p) n=len(p) if not(p.cycle_type()==[2 for i in range(n//2)]): raise ValueError, ("The permutation p (= %s) is not a " "fixed point free involution"%p) objects=Set(range(1,n+1)) data=p.to_cycles() elif ((isinstance(p, list) and all(map(lambda x: (isinstance(x, Integer) or isinstance(x, int)), p))) or isinstance(p, Permutation_class)): p = Permutation(p) n = len(p) if not(p.cycle_type() == [2 for i in range(n//2)]): raise ValueError("The permutation p (= %s) is not a " "fixed point free involution" % p) objects = Set(range(1, n+1)) data = p.to_cycles() # Third case: p is already a perfect matching, we return p directly elif isinstance(p,PerfectMatching): elif isinstance(p, PerfectMatching): return p else: raise ValueError, "cannot convert p (= %s) to a PerfectMatching"%p raise ValueError("cannot convert p (= %s) to a PerfectMatching" % p) # 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 class PerfectMatching(ElementWrapper): EXAMPLES:: sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]);m sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')]);m [('a', 'e'), ('b', 'c'), ('d', 'f')] sage: n=PerfectMatching([3,8,1,7,6,5,4,2]);n sage: n = PerfectMatching([3,8,1,7,6,5,4,2]);n [(1, 3), (2, 8), (4, 7), (5, 6)] """ return '%s'%self.value return '%s' % self.value def _latex_(self): r""" class PerfectMatching(ElementWrapper): EXAMPLES:: sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]) sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')]) sage: m.__hash__() #random 1053935254331348997 sage: hash(m) #indirect doctest #random sage: n=PerfectMatching([3,8,1,7,6,5,4,2]) sage: n = PerfectMatching([3,8,1,7,6,5,4,2]) sage: hash(n) #indirect doctest #random 8097274995140737937 """ return hash(tuple(self.value)) def __eq__(self,other): def __eq__(self, other): r""" Compares two perfect matchings EXAMPLES:: sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]) sage: n=PerfectMatching([('c','b'),('d','f'),('e','a')]) sage: n==m sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')]) sage: n = PerfectMatching([('c','b'),('d','f'),('e','a')]) sage: n == m True sage: n==PerfectMatching([('a','b'),('d','f'),('e','c')]) sage: n == PerfectMatching([('a','b'),('d','f'),('e','c')]) False """ class PerfectMatching(ElementWrapper): return False except AttributeError: return False return Set(map(Set,self.value))==Set(map(Set,other.value)) return Set(map(Set, self.value)) == Set(map(Set, other.value)) def size(self): r""" class PerfectMatching(ElementWrapper): EXAMPLES:: sage: m=PerfectMatching([(-3, 1), (2, 4), (-2, 7)]); m.size() sage: m = PerfectMatching([(-3, 1), (2, 4), (-2, 7)]); m.size() 6 """ return 2*len(self.value) class PerfectMatching(ElementWrapper): EXAMPLES:: sage: m=PerfectMatching([(-3, 1), (2, 4), (-2, 7)]); m.partner(4) sage: m = PerfectMatching([(-3, 1), (2, 4), (-2, 7)]); m.partner(4) 2 sage: n=PerfectMatching([('c','b'),('d','f'),('e','a')]) sage: n = PerfectMatching([('c','b'),('d','f'),('e','a')]) sage: n.partner('c') 'b' """ for i in range(self.size()): if self.value[i][0]==x: if self.value[i][0] == x: return self.value[i][1] if self.value[i][1]==x: if self.value[i][1] == x: return self.value[i][0] raise ValueError,"%s in not an element of the %s"%(x,self) raise ValueError("%s in not an element of the %s" % (x, self)) def conjugate_by_permutation(self, p): r""" class PerfectMatching(ElementWrapper): EXAMPLE:: sage: m=PerfectMatching([(1,4),(2,6),(3,5)]) sage: m = PerfectMatching([(1,4),(2,6),(3,5)]) sage: m.conjugate_by_permutation(Permutation([4,1,5,6,3,2])) [(4, 6), (1, 2), (5, 3)] class PerfectMatching(ElementWrapper): sage: PerfectMatching([]).conjugate_by_permutation(Permutation([])) [] """ return self.parent()(map(lambda t:tuple(map(p,t)),self.value)) return self.parent()(map(lambda t: tuple(map(p, t)), self.value)) def loops_iterator(self,other=None): def loops_iterator(self, other=None): r""" INPUT: class PerfectMatching(ElementWrapper): EXAMPLES:: sage: o=PerfectMatching([(1, 7), (2, 4), (3, 8), (5, 6)]) sage: p=PerfectMatching([(1, 6), (2, 7), (3, 4), (5, 8)]) sage: it=o.loops_iterator(p) sage: o = PerfectMatching([(1, 7), (2, 4), (3, 8), (5, 6)]) sage: p = PerfectMatching([(1, 6), (2, 7), (3, 4), (5, 8)]) sage: it = o.loops_iterator(p) sage: it.next() [1, 7, 2, 4, 3, 8, 5, 6] sage: it.next() class PerfectMatching(ElementWrapper): StopIteration """ if other is None: other=self.parent().an_element() elif self.parent() <> other.parent(): s="%s is not a matching of the ground set of %s"%(other,self) raise ValueError,s remain=flatten(self.value) while len(remain)>0: a=remain.pop(0) b=self.partner(a) other = self.parent().an_element() elif self.parent() != other.parent(): s = "%s is not a matching of the ground set of %s" % (other, self) raise ValueError(s) remain = flatten(self.value) while len(remain) > 0: a = remain.pop(0) b = self.partner(a) remain.remove(b) loop=[a,b] c=other.partner(b) while c<>a: b=self.partner(c) loop = [a, b] c = other.partner(b) while c != a: b = self.partner(c) remain.remove(c) loop.append(c) remain.remove(b) loop.append(b) c=other.partner(b) c = other.partner(b) yield loop def loops(self,other=None): def loops(self, other=None): r""" INPUT: class PerfectMatching(ElementWrapper): EXAMPLES:: sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]) sage: n=PerfectMatching([('a','b'),('d','f'),('e','c')]) sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')]) sage: n = PerfectMatching([('a','b'),('d','f'),('e','c')]) sage: m.loops(n) [['a', 'e', 'c', 'b'], ['d', 'f']] sage: o=PerfectMatching([(1, 7), (2, 4), (3, 8), (5, 6)]) sage: p=PerfectMatching([(1, 6), (2, 7), (3, 4), (5, 8)]) sage: o = PerfectMatching([(1, 7), (2, 4), (3, 8), (5, 6)]) sage: p = PerfectMatching([(1, 6), (2, 7), (3, 4), (5, 8)]) sage: o.loops(p) [[1, 7, 2, 4, 3, 8, 5, 6]] """ class PerfectMatching(ElementWrapper): EXAMPLES:: sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]) sage: n=PerfectMatching([('a','b'),('d','f'),('e','c')]) sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')]) sage: n = PerfectMatching([('a','b'),('d','f'),('e','c')]) sage: m.loop_type(n) [2, 1] TESTS:: sage: m=PerfectMatching([]); m.loop_type() sage: m = PerfectMatching([]); m.loop_type() [] """ return Partition(reversed(sorted([len(l)//2 for l in self.loops_iterator(other)]))) return Partition(reversed( sorted([len(l)//2 for l in self.loops_iterator(other)]))) def number_of_loops(self,other=None): def number_of_loops(self, other=None): r""" INPUT: class PerfectMatching(ElementWrapper): EXAMPLES:: sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]) sage: n=PerfectMatching([('a','b'),('d','f'),('e','c')]) sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')]) sage: n = PerfectMatching([('a','b'),('d','f'),('e','c')]) sage: m.number_of_loops(n) 2 """ class PerfectMatching(ElementWrapper): r""" INPUT: A perfect matching on an *totally ordered* ground set. A perfect matching on a *totally ordered* ground set. OUTPUT: class PerfectMatching(ElementWrapper): EXAMPLES:: sage: n=PerfectMatching([3,8,1,7,6,5,4,2]); n sage: n = PerfectMatching([3,8,1,7,6,5,4,2]); n [(1, 3), (2, 8), (4, 7), (5, 6)] sage: it = n.crossings_iterator(); sage: it.next() class PerfectMatching(ElementWrapper): ... StopIteration """ x=self.value[:] if len(x)==0: x = self.value[:] if len(x) == 0: return (i,j)=x.pop(0) for (a,b) in x: (i, j) = x.pop(0) for (a, b) in x: # if (i