Ticket #8420: trac_8420_features_perfect_matchings_vf.2.patch

File trac_8420_features_perfect_matchings_vf.2.patch, 33.8 KB (added by vferay, 12 years ago)

2nd version, after Florent's comments

  • doc/en/reference/combinat/index.rst

    # HG changeset patch
    # User Valentin Feray <feray at labri.fr>
    # Date 1268215403 -3600
    # Node ID f8fe515f73da8e7fde843fa588a5fd4edf18f179
    # Parent  7712cc516fd20d73f4be0fe0cf768ec83d72ebeb
    #8420 : creation of a class of perfect matchings with several methods
    * * *
    Second version : after Florent's review
    
    diff --git a/doc/en/reference/combinat/index.rst b/doc/en/reference/combinat/index.rst
    a b Combinatorics 
    2828   ../sage/combinat/non_decreasing_parking_function
    2929   ../sage/combinat/partition
    3030   ../sage/combinat/permutation
     31   ../sage/combinat/perfect_matching
    3132   ../sage/combinat/q_analogues
    3233   ../sage/combinat/set_partition_ordered
    3334   ../sage/combinat/set_partition
  • sage/combinat/all.py

    diff --git a/sage/combinat/all.py b/sage/combinat/all.py
    a b from symmetric_group_representations imp 
    1818from yang_baxter_graph import YangBaxterGraph
    1919#from hall_littlewood import HallLittlewood_qp, HallLittlewood_q, HallLittlewood_p
    2020
     21#Permutations
    2122from permutation import Permutation, Permutations, Arrangements, PermutationOptions, CyclicPermutations, CyclicPermutationsOfPartition
    2223
     24#PerfectMatchings
     25from perfect_matching import PerfectMatching, PerfectMatchings
     26
    2327# Integer lists lex
    2428
    2529from integer_list import IntegerListsLex
  • new file sage/combinat/perfect_matching.py

    diff --git a/sage/combinat/perfect_matching.py b/sage/combinat/perfect_matching.py
    new file mode 100644
    - +  
     1r"""
     2Perfect matchings
     3
     4A perfect matching of a set `S` is a partition into 2-element sets. If `S`is
     5the set `{1,..,n}`, it is equivalent to fixpoint-free involutions. These simple
     6combinatorial objects appear in different domains:
     7
     8    - combinatorics of orthogonal polynomials (A. de Medicis et X.Viennot,
     9    Moments des q-polynomes de Laguerre et la bijection de Foata-Zeilberger,
     10    Adv. Appl. Math., 15 (1994), 262-304)
     11
     12    - combinatorics of hyperoctahedral group, double coset algebra and zonal
     13    polynomials (I. G. Macdonald, Symmetric functions and Hall polynomials,
     14    Oxford University Press, second edition, 1995, chapter VII).
     15
     16AUTHOR:
     17
     18    - Valentin Feray, 2010 : initial version
     19
     20EXAMPLES:
     21
     22    Create a perfect matching::
     23
     24        sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]);m
     25        PerfectMatching [('a', 'e'), ('b', 'c'), ('d', 'f')]
     26
     27    Count its crossings, if the ground set is totally ordered::
     28
     29        sage: n=PerfectMatching([3,8,1,7,6,5,4,2]); n
     30        PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)]
     31        sage: n.number_of_crossings()
     32        1
     33
     34    List the perfect matchings of a given ground set::
     35
     36        sage: PerfectMatchings(4).list()
     37        [PerfectMatching [(4, 1), (3, 2)], PerfectMatching [(4, 2), (3, 1)], PerfectMatching [(4, 3), (2, 1)]]
     38
     39#*****************************************************************************
     40#       Copyright (C) 2010 Valentin Feray <feray@labri.fr>
     41#
     42#  Distributed under the terms of the GNU General Public License (GPL)
     43#                  http://www.gnu.org/licenses/
     44#*****************************************************************************
     45
     46"""
     47
     48#from sage.combinat.permutation import Permutation_Class
     49from sage.structure.unique_representation import UniqueRepresentation
     50from sage.structure.parent import Parent
     51from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
     52from sage.misc.classcall_metaclass import ClasscallMetaclass
     53from sage.structure.element_wrapper import ElementWrapper
     54from sage.structure.element import Element
     55from sage.misc.cachefunc import cached_method
     56from sage.rings.integer import Integer
     57from sage.misc.flatten import flatten
     58from sage.combinat.permutation import Permutation
     59from sage.sets.set import Set
     60from sage.combinat.partition import Partition
     61from sage.misc.misc_c import prod
     62from sage.matrix.constructor import Matrix
     63
     64class PerfectMatching(ElementWrapper):
     65    r"""
     66    Class of perfect matching.
     67
     68    An instance of the class can be created from a list of pairs or from a
     69    fixed point-free involution as follows::
     70
     71        sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]);m
     72        PerfectMatching [('a', 'e'), ('b', 'c'), ('d', 'f')]
     73        sage: n=PerfectMatching([3,8,1,7,6,5,4,2]);n
     74        PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)]
     75        sage: isinstance(m,PerfectMatching)
     76        True
     77
     78    The parent, which is the set of perfect matching of the ground set, is
     79    automaticly created::
     80
     81        sage: n.parent()
     82        Set of perfect matchings of {1, 2, 3, 4, 5, 6, 7, 8}
     83
     84    If the ground set is ordered, one can, for example, ask if the matching is
     85    non crossing::
     86
     87        sage: PerfectMatching([(1, 4), (2, 3), (5, 6)]).is_non_crossing()
     88        True
     89
     90    TESTS::
     91
     92        sage: m=PerfectMatching([]); m
     93        PerfectMatching []
     94        sage: m.parent()
     95        Set of perfect matchings of {}
     96    """
     97    #the data structure of the element is a list (accessible via x.value)
     98    wrapped_class = list
     99    __lt__ = ElementWrapper._lt_by_value
     100    #During the creation of the instance of the class, the function
     101    #__classcall_private__ will be called instead of __init__ directly.
     102    __metaclass__ = ClasscallMetaclass
     103
     104    @staticmethod
     105    def __classcall_private__(cls,p):
     106        r"""
     107        This function tries to recognize the input (it can be either a list or
     108        a tuple of pairs, or a fix-point free involution given as a list or as
     109        a permutation), constructs the parent (enumerated set of
     110        PerfectMatchings of the ground set) and calls the __init__ function to
     111        construct our object.
     112
     113        EXAMPLES::
     114
     115            sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]);m
     116            PerfectMatching [('a', 'e'), ('b', 'c'), ('d', 'f')]
     117            sage: isinstance(m,PerfectMatching)
     118            True
     119            sage: n=PerfectMatching([3, 8, 1, 7, 6, 5, 4, 2]);n
     120            PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)]
     121            sage: n.parent()
     122            Set of perfect matchings of {1, 2, 3, 4, 5, 6, 7, 8}
     123            sage: PerfectMatching([(1, 4), (2, 3), (5, 6)]).is_non_crossing()
     124            True
     125
     126        The function checks that the given list or permutation is a valid perfect
     127        matching (i.e. a list of pairs with pairwise disjoint elements  or a
     128        fixpoint-free involution) and raises a ValueError otherwise:
     129
     130            sage: try:
     131            ...    m=PerfectMatching([(1, 2, 3), (4, 5)])
     132            ... except ValueError:
     133            ...    "A ValueError has been raised."
     134            'A ValueError has been raised.'
     135       
     136        If you know your datas are in a good format, use directly
     137        `PerfectMatchings(objects)(data)`.         
     138        """
     139        # we have to extract from the argument p the set of objects of the
     140        # matching and the list of pairs.
     141        # First case: p is a list (resp tuple) of lists (resp tuple).
     142        if (isinstance(p,list) or isinstance(p,tuple)) and (
     143                all([isinstance(x,list) or isinstance(x,tuple) for x in p])):
     144            objects=Set(flatten(p))
     145            data=(map(tuple,p))
     146            #check if the data are correct
     147            if not all([len(t)==2 for t in data]):
     148                raise ValueError, "%s is not a valid perfect matching: all elements of the list must be pairs"%p
     149            if len(objects) < 2*len(data):
     150                raise ValueError, "%s is not a valid perfect matching: there are some repetitions"%p
     151        # Second case: p is a permutation or a list of integers, we have to
     152        # check if it is a fix-point-free involution.
     153        elif ((isinstance(p,list) and
     154            all(map(lambda x: (isinstance(x,Integer) or isinstance(x,int)),p )))
     155            or isinstance(p,sage.combinat.permutation.Permutation_class)):
     156            p=Permutation(p)
     157            n=len(p)
     158            if not(p.cycle_type()==[2 for i in range(n//2)]):
     159                s="The permutation p (= %s) is not a fixpoint-free involution"%p
     160                raise ValueError,s
     161            objects=Set(range(1,n+1))
     162            data=p.to_cycles()
     163        # Third case: p is already a perfect matching, we return p directly
     164        elif isinstance(p,PerfectMatching):
     165            return p
     166        else:
     167            raise ValueError, "cannot convert p (= %s) to a PerfectMatching"%p
     168        # Finally, we create the parent and the element using the element
     169        # class of the parent. Note: as this function is private, when we
     170        # create an object via parent.element_class(...), __init__ is directly
     171        # executed and we do not have an infinite loop.
     172        return PerfectMatchings(objects)(data)
     173
     174    def __init__(self,data,parent):
     175        r"""
     176        See :meth:`__classcall_private__`
     177
     178        TESTS::
     179
     180            sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')])
     181            sage: TestSuite(m).run()
     182        """
     183        self.value=data
     184        Element.__init__(self,parent=parent)
     185
     186    def _repr_(self):
     187        r"""
     188        returns the name of the object
     189
     190        EXAMPLES::
     191
     192            sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')]);m
     193            PerfectMatching [('a', 'e'), ('b', 'c'), ('d', 'f')]
     194            sage: n=PerfectMatching([3,8,1,7,6,5,4,2]);n
     195            PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)]
     196        """
     197        return 'PerfectMatching %s'%self.value
     198
     199    def __eq__(self,other):
     200        r"""
     201        Compares two perfect matchings
     202
     203        EXAMPLES::
     204
     205            sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')])
     206            sage: n=PerfectMatching([('c','b'),('d','f'),('e','a')])
     207            sage: n==m
     208            True
     209            sage: n==PerfectMatching([('a','b'),('d','f'),('e','c')])
     210            False
     211
     212        """
     213        try:
     214            if other.parent() != self.parent():
     215                return False
     216        except AttributeError:
     217            return False
     218        return Set(map(Set,self.value))==Set(map(Set,other.value))
     219
     220    def size(self):
     221        r"""
     222
     223        Returns the size of the perfect matching ``self``, i.e. the number of
     224        elements in the ground set.
     225
     226        EXAMPLES::
     227
     228            sage: m=PerfectMatching([(-3, 1), (2, 4), (-2, 7)]); m.size()
     229            6
     230        """
     231        return 2*len(self.value)
     232
     233    def partner(self, x):
     234        r"""
     235        Returns the element in the same pair than ``x`` in the matching ``self``.
     236
     237        EXAMPLES::
     238
     239            sage: m=PerfectMatching([(-3, 1), (2, 4), (-2, 7)]); m.partner(4)
     240            2
     241            sage: n=PerfectMatching([('c','b'),('d','f'),('e','a')])
     242            sage: n.partner('c')
     243            'b'
     244        """
     245        for i in range(self.size()):
     246            if self.value[i][0]==x:
     247                return self.value[i][1]
     248            if self.value[i][1]==x:
     249                return self.value[i][0]
     250        raise ValueError,"%s in not an element of the %s"%(x,self)
     251
     252    def conjugate_by_permutation(self, p):
     253        r"""
     254        Returns the conjugate of the perfect matching ``self`` by the
     255        permutation ``p`` of the ground set.
     256
     257        EXAMPLE::
     258
     259            sage: m=PerfectMatching([(1,4),(2,6),(3,5)])
     260            sage: m.conjugate_by_permutation(Permutation([4,1,5,6,3,2]))
     261            PerfectMatching [(4, 6), (1, 2), (5, 3)]
     262
     263        TEST::
     264
     265            sage: PerfectMatching([]).conjugate_by_permutation(Permutation([]))
     266            PerfectMatching []
     267        """
     268        return self.parent()(map(lambda t:tuple(map(p,t)),self.value))
     269
     270    def loops_iterator(self,other=None):
     271        r"""
     272        INPUT:
     273
     274             - ``other`` -- a perfect matching of the same set of ``self``.
     275             (if the second argument is empty, the method :meth:`an_element` is
     276             called on the parent of the first)
     277
     278        OUTPUT:
     279
     280            If we draw the two perfect matchings simultaneously as edges of a
     281            graph, the graph obtained is a union of cycles of even lengths.
     282            The function returns an iterator for these cycles (each cycle is
     283            given as a list).
     284
     285        EXAMPLES::
     286
     287            sage: o=PerfectMatching([(1, 7), (2, 4), (3, 8), (5, 6)])
     288            sage: p=PerfectMatching([(1, 6), (2, 7), (3, 4), (5, 8)])
     289            sage: it=o.loops_iterator(p)
     290            sage: it.next()
     291            [1, 7, 2, 4, 3, 8, 5, 6]
     292            sage: it.next()
     293            Traceback (most recent call last):
     294            ...
     295            StopIteration
     296        """
     297        if other is None:
     298            other=self.parent().an_element()
     299        elif self.parent() <> other.parent():
     300            s="%s is not a matching of the ground set of %s"%(other,self)
     301            raise ValueError,s
     302        remain=flatten(self.value)
     303        while len(remain)>0:
     304            a=remain.pop(0)
     305            b=self.partner(a)
     306            remain.remove(b)
     307            loop=[a,b]
     308            c=other.partner(b)
     309            while c<>a:
     310                b=self.partner(c)
     311                remain.remove(c)
     312                loop.append(c)
     313                remain.remove(b)
     314                loop.append(b)
     315                c=other.partner(b)
     316            yield loop
     317
     318    def loops(self,other=None):
     319        r"""
     320        INPUT:
     321
     322             - ``other`` -- a perfect matching of the same set of ``self``.
     323             (if the second argument is empty, the method :meth:`an_element` is
     324             called on the parent of the first)
     325
     326        OUTPUT:
     327
     328            If we draw the two perfect matchings simultaneously as edges of a
     329            graph, the graph obtained is a union of cycles of even lengths.
     330            The function returns the list of these cycles (each cycle is given
     331            as a list).
     332
     333        EXAMPLES::
     334
     335            sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')])
     336            sage: n=PerfectMatching([('a','b'),('d','f'),('e','c')])
     337            sage: m.loops(n)
     338            [['a', 'e', 'c', 'b'], ['d', 'f']]
     339            sage: o=PerfectMatching([(1, 7), (2, 4), (3, 8), (5, 6)])
     340            sage: p=PerfectMatching([(1, 6), (2, 7), (3, 4), (5, 8)])
     341            sage: o.loops(p)
     342            [[1, 7, 2, 4, 3, 8, 5, 6]]
     343        """
     344        return list(self.loops_iterator(other))
     345
     346    def loop_type(self, other=None):
     347        r"""
     348        INPUT:
     349
     350             - ``other`` -- a perfect matching of the same set of ``self``.
     351             (if the second argument is empty, the method :meth:`an_element` is
     352             called on the parent of the first)
     353
     354        OUTPUT:
     355
     356            If we draw the two perfect matchings simultaneously as edges of a
     357            graph, the graph obtained is a union of cycles of even
     358            lengths. The function returns the ordered list of the semi-length
     359            of these cycles (considered as a partition)
     360
     361        EXAMPLES::
     362
     363            sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')])
     364            sage: n=PerfectMatching([('a','b'),('d','f'),('e','c')])
     365            sage: m.loop_type(n)
     366            [2, 1]
     367
     368        TESTS::
     369
     370            sage: m=PerfectMatching([]); m.loop_type()
     371            []
     372        """
     373        return Partition(reversed(sorted([len(l)//2
     374            for l in self.loops_iterator(other)])))       
     375
     376    def number_of_loops(self,other=None):
     377        r"""
     378        INPUT:
     379
     380            - ``other`` -- a perfect matching of the same set of ``self``.
     381            (if the second argument is empty, the fonction an_element is
     382            called on the parent of the first)
     383
     384        OUTPUT:
     385
     386            If we draw the two perfect matchings simultaneously as edges of a
     387            graph, the graph obtained is a union of cycles of even lengths.
     388            The function returns their numbers.
     389
     390        EXAMPLES::
     391
     392            sage: m=PerfectMatching([('a','e'),('b','c'),('d','f')])
     393            sage: n=PerfectMatching([('a','b'),('d','f'),('e','c')])
     394            sage: m.number_of_loops(n)
     395            2
     396        """
     397        c = Integer(0)
     398        one = Integer(1)
     399        for _ in self.loops_iterator(other):
     400            c += one
     401        return c
     402
     403    def crossings_iterator(self):
     404        r"""
     405        INPUT:
     406
     407            A perfect matching on an *totally ordered* ground set.
     408
     409        OUTPUT:
     410
     411            We place the element of a ground set and draw the perfect matching
     412            by linking the elements of the same pair in the upper
     413            half-plane. This function returns an iterator over the pairs of
     414            crossing lines (as a line correspond to a pair, the iterator
     415            produces pairs of pairs).
     416
     417        EXAMPLES::
     418
     419            sage: n=PerfectMatching([3,8,1,7,6,5,4,2]); n
     420            PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)]
     421            sage: it = n.crossings_iterator();
     422            sage: it.next()
     423            ((1, 3), (2, 8))
     424            sage: it.next()
     425            Traceback (most recent call last):
     426            ...
     427            StopIteration
     428        """
     429        x=self.value[:]
     430        if len(x)==0:
     431            return
     432        (i,j)=x.pop(0)
     433        for (a,b) in x:
     434            # if (i<a<j<b) or (i<b<j<a) or (j<a<i<b) or (j<b<i<a) or (
     435            #        a<i<b<j) or (a<j<b<i) or (b<i<a<j) or (b<j<a<i):
     436            labij = sorted([a,b,i,j])
     437            posij = sorted([labij.index(i), labij.index(j)])
     438            if posij == [0,2] or posij == [1,3]:
     439                yield ((i,j),(a,b))
     440        for cr in PerfectMatchings(flatten(x))(x).crossings_iterator():
     441            yield cr
     442
     443    def crossings(self):
     444        r"""
     445        INPUT:
     446
     447            A perfect matching on an *totally ordered* ground set.
     448
     449        OUTPUT:
     450
     451            We place the element of a ground set and draw the perfect matching
     452            by linking the elements of the same pair in the upper
     453            half-plane. This function returns the list of the pairs of
     454            crossing lines (as a line correspond to a pair, it returns a list
     455            of pairs of pairs).
     456
     457        EXAMPLES::
     458
     459            sage: n=PerfectMatching([3,8,1,7,6,5,4,2]); n
     460            PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)]
     461            sage: n.crossings()
     462            [((1, 3), (2, 8))]
     463
     464        TESTS::
     465
     466            sage: m=PerfectMatching([]); m.crossings()
     467            []
     468        """
     469        return list(self.crossings_iterator())
     470
     471    def number_of_crossings(self):
     472        r"""
     473        INPUT:
     474
     475            A perfect matching on an *totally ordered* ground set.
     476
     477        OUTPUT:
     478
     479            We place the element of a ground set and draw the perfect matching
     480            by linking the elements of the same pair in the upper
     481            half-plane. This function returns the number the pairs of crossing
     482            lines.
     483
     484        EXAMPLES::
     485
     486            sage: n=PerfectMatching([3,8,1,7,6,5,4,2]); n
     487            PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)]
     488            sage: n.number_of_crossings()
     489            1
     490        """
     491        c = Integer(0)
     492        one = Integer(1)
     493        for _ in self.crossings_iterator():
     494            c += one
     495        return c
     496
     497    def is_non_crossing(self):
     498        r"""
     499        INPUT:
     500
     501            A perfect matching on an *totally ordered* ground set.
     502
     503        OUTPUT:
     504
     505            We place the element of a ground set and draw the perfect matching
     506            by linking the elements of the same pair in the upper
     507            half-plane. This function returns ``True`` if the picture obtained
     508            this way has no crossings.
     509
     510        EXAMPLES::
     511
     512            sage: n=PerfectMatching([3,8,1,7,6,5,4,2]); n
     513            PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)]
     514            sage: n.is_non_crossing()
     515            False
     516            sage: PerfectMatching([(1, 4), (2, 3), (5, 6)]).is_non_crossing()
     517            True
     518        """
     519        it = self.crossings_iterator()
     520        try:
     521            it.next()
     522        except StopIteration:
     523            return True
     524        else:
     525            return False
     526
     527    def nestings_iterator(self):
     528        r"""
     529        INPUT:
     530
     531            A perfect matching on an *totally ordered* ground set.
     532
     533        OUTPUT:
     534
     535            We place the element of a ground set and draw the perfect matching
     536            by linking the elements of the same pair in the upper
     537            half-plane. This function returns an iterator over the pairs of
     538            nesting lines (as a line correspond to a pair, the iterator
     539            produces pairs of pairs).
     540
     541        EXAMPLES::
     542
     543            sage: n=PerfectMatching([(1, 6), (2, 7), (3, 5), (4, 8)])
     544            sage: it = n.nestings_iterator();
     545            sage: it.next()
     546            ((1, 6), (3, 5))
     547            sage: it.next()
     548            ((2, 7), (3, 5))
     549            sage: it.next()
     550            Traceback (most recent call last):
     551            ...
     552            StopIteration
     553        """
     554        x=self.value[:]
     555        if len(x)==0:
     556            return
     557        (i,j)=x.pop(0)
     558        for (a,b) in x:
     559            # if (i<a<j<b) or (i<b<j<a) or (j<a<i<b) or (j<b<i<a) or (
     560            #        a<i<b<j) or (a<j<b<i) or (b<i<a<j) or (b<j<a<i):
     561            labij = sorted([a,b,i,j])
     562            posij = sorted([labij.index(i), labij.index(j)])
     563            if posij == [0,3] or posij == [1,2]:
     564                yield ((i,j),(a,b))
     565        for nest in PerfectMatchings(flatten(x))(x).nestings_iterator():
     566            yield nest
     567
     568    def nestings(self):
     569        r"""
     570        INPUT:
     571
     572            A perfect matching on an *totally ordered* ground set.
     573
     574        OUTPUT:
     575
     576            We place the element of a ground set and draw the perfect matching
     577            by linking the elements of the same pair in the upper
     578            half-plane. This function returns the list of the pairs of
     579            nesting lines (as a line correspond to a pair, it returns a list
     580            of pairs of pairs).
     581
     582        EXAMPLES::
     583
     584            sage: m=PerfectMatching([(1, 6), (2, 7), (3, 5), (4, 8)])
     585            sage: m.nestings()
     586            [((1, 6), (3, 5)), ((2, 7), (3, 5))]
     587            sage: n=PerfectMatching([3,8,1,7,6,5,4,2]); n
     588            PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)]
     589            sage: n.nestings()
     590            [((2, 8), (4, 7)), ((2, 8), (5, 6)), ((4, 7), (5, 6))]
     591
     592        TESTS::
     593
     594            sage: m=PerfectMatching([]); m.nestings()
     595            []
     596        """
     597        return list(self.nestings_iterator())
     598
     599    def number_of_nestings(self):
     600        r"""
     601        INPUT:
     602
     603            A perfect matching on an *totally ordered* ground set.
     604
     605        OUTPUT:
     606
     607            We place the element of a ground set and draw the perfect matching
     608            by linking the elements of the same pair in the upper
     609            half-plane. This function returns the number the pairs of nesting
     610            lines.
     611
     612        EXAMPLES::
     613
     614            sage: n=PerfectMatching([3,8,1,7,6,5,4,2]); n
     615            PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)]
     616            sage: n.number_of_nestings()
     617            3
     618        """
     619        c = Integer(0)
     620        one = Integer(1)
     621        for _ in self.nestings_iterator():
     622            c += one
     623        return c
     624
     625    def is_non_nesting(self):
     626        r"""
     627        INPUT:
     628
     629            A perfect matching on an *totally ordered* ground set.
     630
     631        OUTPUT:
     632
     633            We place the element of a ground set and draw the perfect matching
     634            by linking the elements of the same pair in the upper
     635            half-plane. This function returns ``True`` if the picture obtained
     636            this way has no nestings.
     637
     638        EXAMPLES::
     639
     640            sage: n=PerfectMatching([3,8,1,7,6,5,4,2]); n
     641            PerfectMatching [(1, 3), (2, 8), (4, 7), (5, 6)]
     642            sage: n.is_non_nesting()
     643            False
     644            sage: PerfectMatching([(1, 3), (2, 5), (4, 6)]).is_non_nesting()
     645            True
     646        """
     647        it = self.nestings_iterator()
     648        try:
     649            it.next()
     650        except StopIteration:
     651            return True
     652        else:
     653            return False
     654
     655    def Weingarten_function(self,d,other=None):
     656        r"""
     657        Returns the Weingarten function of two pairings. This function is
     658        the value of some integrals over the orhtogonal groups `O_N`
     659       
     660        Reference : Benoit Collins, Sho Matsumoto, On some properties of
     661        orthogonal Weingarten functions, arXiv:0903.5143
     662        With the convention of this article, the function returns
     663        `Wg^{O(d)}(other,self)`.
     664
     665        EXAMPLES::
     666
     667            sage: var('N')
     668            N
     669            sage: m=PerfectMatching([(1,3),(2,4)])
     670            sage: n=PerfectMatching([(1,2),(3,4)])
     671            sage: factor(m.Weingarten_function(N,n))
     672            -1/((N - 1)*(N + 2)*N)
     673        """
     674        if other is None:
     675            other = self.parent().an_element()
     676        W=self.parent().Weingarten_matrix(d)
     677        return W[other.rank()][self.rank()]
     678
     679class PerfectMatchings(UniqueRepresentation,Parent):
     680    r"""
     681    Class of perfect matchings of a ground set. At the creation, the set
     682    can be given as any iterable object. If the argument is an integer `n`, it
     683    will be transformed into `[1 .. n]`::
     684
     685        sage: M=PerfectMatchings(6);M
     686        Set of perfect matchings of {1, 2, 3, 4, 5, 6}
     687        sage: PerfectMatchings([-1, -3, 1, 2])
     688        Set of perfect matchings of {1, 2, -3, -1}
     689
     690    One can ask for the list, the cardinality or an element of a set of
     691    perfect matching::
     692
     693        sage: PerfectMatchings(4).list()
     694        [PerfectMatching [(4, 1), (3, 2)], PerfectMatching [(4, 2), (3, 1)], PerfectMatching [(4, 3), (2, 1)]]
     695        sage: PerfectMatchings(8).cardinality()
     696        105
     697        sage: M=PerfectMatchings(('a', 'e', 'b', 'f', 'c', 'd'))
     698        sage: M.an_element()
     699        PerfectMatching [('a', 'e'), ('c', 'd'), ('b', 'f')]
     700        sage: all([PerfectMatchings(i).an_element() in PerfectMatchings(i)
     701        ...        for i in range(2,11,2)])
     702        True
     703
     704    TESTS::
     705
     706        sage: PerfectMatchings(5).list()
     707        []
     708    """
     709
     710    @staticmethod
     711    def _parse_input(objects):
     712        r"""
     713        This function tries to recognize the argument and to transform into a
     714        set. It is not meant to be called manually, but only as the first of
     715        the creation of an enumerated set of ``PerfectMatchings``.
     716
     717        EXAMPLES::
     718
     719            sage: PerfectMatchings._parse_input(4)
     720            {1, 2, 3, 4}
     721            sage: PerfectMatchings._parse_input(['a','b','c','e'])
     722            {'a', 'c', 'b', 'e'}
     723        """
     724        # if the argument is a python int n, we replace it by the list [1 .. n]
     725        if isinstance(objects,int):
     726            objects=range(1,objects+1)
     727        # same thing if the argument is a sage integer.
     728        elif isinstance(objects,Integer):
     729            objects=range(1,objects+1)
     730        # Finally, if it is iterable, we return the corresponding set.
     731        # Note that it is important to return a hashable object here (in
     732        # particular, NOT A LIST), see comment below.
     733        if not hasattr(objects,'__iter__'):
     734            raise ValueError, "do not know how to construct a set of matchings from %s (it must be iterable)"
     735        return Set(objects)
     736
     737    @staticmethod
     738    def __classcall__(cls, objects):
     739        r"""
     740        This function is called automatically when the user want to
     741        create an enumerated set of PerfectMatchings.
     742
     743        EXAMPLES::
     744
     745            sage: M=PerfectMatchings(6);M
     746            Set of perfect matchings of {1, 2, 3, 4, 5, 6}
     747            sage: PerfectMatchings([-1, -3, 1, 2])
     748            Set of perfect matchings of {1, 2, -3, -1}
     749
     750        If one has already created a set of perfect matchings of the same set,
     751        it does not create a new object, but returns the already existing
     752        one::
     753
     754            sage: N=PerfectMatchings((2, 3, 5, 4, 1, 6))
     755            sage: N is M
     756            True
     757        """
     758        #we call the constructor of an other class, which will
     759        #    - check if the object has already been constructed (so the
     760        # second argument, i.e. the output of _parse_input, must be hashable)
     761        #    - look for a place in memory and call the __init__ function
     762        return super(PerfectMatchings, cls).__classcall__(
     763                         cls, cls._parse_input(objects))
     764
     765    def __init__(self,objects):
     766        r"""
     767        See :meth:`__classcall__`
     768
     769        TEST::
     770
     771            sage: M=PerfectMatchings(6)
     772            sage: TestSuite(M).run()
     773        """
     774        self._objects=objects
     775        Parent.__init__(self, category = FiniteEnumeratedSets())
     776
     777    def _repr_(self):
     778        r"""
     779        Returns a description of ``self``.
     780
     781        EXAMPLES::
     782
     783            sage: PerfectMatchings([-1, -3, 1, 2])
     784            Set of perfect matchings of {1, 2, -3, -1}
     785        """
     786        return "Set of perfect matchings of %s"%self._objects
     787
     788    def __iter__(self):
     789        r"""
     790        Returns an iterator for the elements of ``self``.
     791
     792        EXAMPLES::
     793
     794            sage: PerfectMatchings(4).list()
     795            [PerfectMatching [(4, 1), (3, 2)], PerfectMatching [(4, 2), (3, 1)], PerfectMatching [(4, 3), (2, 1)]]
     796        """
     797        if len(self._objects) == 0:
     798            yield self([])
     799        elif len(self._objects) == 1:
     800            pass
     801        else:
     802            l=list(self._objects)
     803            a=l.pop(-1)
     804            for i in range(len(l)):
     805                obj_rest=l[:]
     806                b=obj_rest.pop(i)
     807                for p in PerfectMatchings(obj_rest):
     808                    yield self([(a, b)]+p.value)
     809
     810    def __contains__(self,x):
     811        r"""
     812        Tests if ``x`` is an element of ``self``.
     813
     814        EXAMPLES::
     815
     816            sage: m=PerfectMatching([(1,2),(4,3)])
     817            sage: m in PerfectMatchings(4)
     818            True
     819            sage: m in PerfectMatchings((0, 1, 2, 3))
     820            False
     821            sage: all([m in PerfectMatchings(6) for m in PerfectMatchings(6)])
     822            True
     823
     824        Note that the class of ``x`` does not need to be ``PerfectMatching``:
     825        if the data defines a perfect matching of the good set, the function
     826        returns ``True``::
     827
     828            sage: [(1, 4), (2, 3)] in PerfectMatchings(4)
     829            True
     830            sage: [(1, 3, 6), (2, 4), (5,)] in PerfectMatchings(6)
     831            False
     832            sage: [('a', 'b'), ('a', 'c')] in PerfectMatchings(
     833            ...        ('a', 'b', 'c', 'd'))
     834            False
     835        """
     836        if not isinstance(x,PerfectMatching):
     837            try:
     838                x=PerfectMatching(x)
     839            except ValueError:
     840                return False
     841        if x.parent() is not self:
     842            return False
     843        return True
     844
     845    def cardinality(self):
     846        r"""
     847        Returns the cardinality of the set of perfect matching ``self``,
     848        that is `1*3*5*...*(2n-1)`, where `2n` is the size of the ground set.
     849
     850        EXAMPLES::
     851
     852            sage: PerfectMatchings(8).cardinality()
     853            105
     854        """
     855        n=len(self._objects)
     856        if n%2==1:
     857            return 0
     858        else:
     859            return prod(i for i in range(n) if i%2==1)
     860
     861    def an_element(self):
     862        r"""
     863        Returns an element of self.
     864
     865        EXAMPLES::
     866
     867            sage: M=PerfectMatchings(('a', 'e', 'b', 'f', 'c', 'd'))
     868            sage: M.an_element()
     869            PerfectMatching [('a', 'e'), ('c', 'd'), ('b', 'f')]
     870            sage: all([PerfectMatchings(i).an_element() in PerfectMatchings(i)
     871            ...        for i in range(2,11,2)])
     872            True
     873        """
     874        n=len(self._objects)//2
     875        return self([(self._objects[i],self._objects[i+n])
     876                                for i in range(n)])
     877
     878    @cached_method
     879    def Weingarten_matrix(self,N):
     880        r"""
     881        Returns the Weingarten matrix corresponding to the set of
     882        PerfectMatchings ``self``. It is a useful theoretical tool to compute
     883        polynomial integral over the orthogonal group `O_N`.
     884
     885        Reference : Benoit Collins, Sho Matsumoto, On some properties of
     886        orthogonal Weingarten functions, arXiv:0903.5143
     887
     888        EXAMPLES::
     889
     890            sage: M=PerfectMatchings(4).Weingarten_matrix(var('N'))
     891            sage: N*(N-1)*(N+2)*M.apply_map(factor)
     892            [N + 1    -1    -1]
     893            [   -1 N + 1    -1]
     894            [   -1    -1 N + 1]
     895        """
     896        G=Matrix([ [N**(p1.number_of_loops(p2)) for p1 in self]
     897            for p2 in self])
     898        return G**(-1)
     899
     900    Element=PerfectMatching
  • sage/combinat/permutation.py

    diff --git a/sage/combinat/permutation.py b/sage/combinat/permutation.py
    a b class Permutation_class(CombinatorialObj 
    25892589            i -= 1
    25902590        return Permutation_class(self[:i+1])                   
    25912591       
    2592        
     2592    def coset_type(self):
     2593        from sage.combinat.perfect_matching import PerfectMatchings
     2594        r"""       
     2595        returns the coset type of ``self``, which must be a permutation of even
     2596        size `2n`. The coset-type determines the double class of the
     2597        permutation, that is its image in `H_n \ S_2n / H_n`, where `H_n` is the
     2598        hyperoctahedral group of order `n`. See I. G. Macdonald, Symmetric
     2599        functions and Hall polynomials, Oxford University Press, second edition,
     2600        1995 (chapter VII) for more details.
     2601
     2602        EXAMPLE::
     2603
     2604            sage: Permutation([3, 4, 6, 1, 5, 7, 2, 8]).coset_type()
     2605            [3, 1]
     2606            sage: all([p.coset_type()==p.inverse().coset_type()
     2607            ...         for p in Permutations(4)])
     2608            True
     2609        """
     2610        n = len(self)
     2611        if n%2==1:
     2612            raise ValueError, "%s is a permutation of odd size and has no coset-type"%p
     2613        S=PerfectMatchings(n)([(2*i+1,2*i+2) for i in range(n//2)])
     2614        return S.loop_type(S.conjugate_by_permutation(self))
    25932615
    25942616################################################################
    25952617