Beispiel #1
0
        def coproduct_on_basis(self, x):
            r"""
            Return the coproduct of `F_{\sigma}` for `\sigma` a permutation.

            EXAMPLES::

                sage: A = algebras.FQSym(QQ).F()
                sage: x = A([1])
                sage: ascii_art(A.coproduct(A.one()))  # indirect doctest
                1 # 1

                sage: ascii_art(A.coproduct(x))  # indirect doctest
                1 # F    + F    # 1
                     [1]    [1]

                sage: A = algebras.FQSym(QQ).F()
                sage: x, y, z = A([1]), A([2,1]), A([3,2,1])
                sage: A.coproduct(z)
                F[] # F[3, 2, 1] + F[1] # F[2, 1] + F[2, 1] # F[1]
                + F[3, 2, 1] # F[]
            """
            if not len(x):
                return self.one().tensor(self.one())
            return sum(
                self(Word(x[:i]).standard_permutation()).tensor(
                    self(Word(x[i:]).standard_permutation()))
                for i in range(len(x) + 1))
Beispiel #2
0
    def __iter__(self):
        """
        TESTS::

            sage: WeightedIntegerVectors(7, [2,2]).list()
            []
            sage: WeightedIntegerVectors(3, [2,1,1]).list()
            [[1, 0, 1], [1, 1, 0], [0, 0, 3], [0, 1, 2], [0, 2, 1], [0, 3, 0]]

        ::

            sage: ivw = [ WeightedIntegerVectors(k, [1,1,1]) for k in range(11) ]
            sage: iv  = [ IntegerVectors(k, 3) for k in range(11) ]
            sage: all( [ sorted(iv[k].list()) == sorted(ivw[k].list()) for k in range(11) ] )
            True

        ::

            sage: ivw = [ WeightedIntegerVectors(k, [2,3,7]) for k in range(11) ]
            sage: all( [ i.cardinality() == len(i.list()) for i in ivw] )
            True
        """
        if len(self._weights) == 0:
            if self._n == 0:
                yield []
            return

        perm = Word(self._weights).standard_permutation()
        l = [x for x in sorted(self._weights)]
        for x in self._recfun(self._n, l):
            yield perm.action(x)
Beispiel #3
0
    def to_word(self, use_str=True, upper_case_as_inverse=True):
        """
        Convert ``self`` to a word.

        A free group element is a reduced words in the generators and their
        inverses. This is naturally a finite word. Some choices have to be
        done:

        1. ``use_str==True``: the letters of the words are strings
           (possibly a single character, but not necessarily).

           ``use_str==False``: the letters of the word are the generators
           and their inverses themselves, that is to say the letters are
           FreeGroupElement.

         2. ``upper_case_as_inverse==True``: the inverse of a generator is
            written as the same string in upper case. This is used only with
            the ``use_string==True`` option.


        INPUT:

        - ``use_str`` -- (default: ``True``) use strings rather than
          :class:`FreeGroupElement` as letters
        - ``upper_case_as_inverse`` -- (default: ``True``) use upper case
          letters as inverses

        OUTPUT:

        A finite :class:`~sage.combinat.words.finite_word.FiniteWord_class`.

        EXAMPLES::

            sage: from train_track import *
            sage: F = FreeGroup(3)
            sage: w = F([1,-2,1,3,-1])
            sage: w.to_word()
            word: x0,X1,x0,x2,X0
            sage: type(w.to_word()[1])
            <... 'str'>
            sage: w.to_word(use_str=False)
            word: x0,x1^-1,x0,x2,x0^-1
            sage: w.to_word(use_str=False)[1] == w[1]
            True
        """
        from sage.combinat.words.word import Word

        if use_str and upper_case_as_inverse:
            wt = self.Tietze()
            A = self.parent().variable_names()
            w = []
            for a in wt:
                if a > 0:
                    w.append(A[a - 1])
                else:
                    w.append(A[-a - 1].upper())
            return Word(w)
        if use_str:
            return Word([str(a) for a in self])
        return Word(list(self))
Beispiel #4
0
    def spanning_tree(self, verbose=False):
        """
          A spanning tree.

          OUPUT:

          a dictionnary that maps each vertex to an edge-path from the origin vertex.

          SEE ALSO:

          ``maximal_tree()`` that returns a list of edges of a spanning tree.

          WARNING:

          ``self`` must be connected.
          """

        A = self._alphabet
        tree = {self.initial_vertex(A[0]): Word()}

        done = False
        while not done:
            done = True
            for a in A.positive_letters():
                vi = self.initial_vertex(a)
                vt = self.terminal_vertex(a)
                if vi in tree and vt not in tree:
                    tree[vt] = self.reduce_path(tree[vi] * Word([a]))
                    done = False
                elif vt in tree and vi not in tree:
                    tree[vi] = self.reduce_path(tree[vt] *
                                                Word([A.inverse_letter(a)]))
                    done = False
        return tree
 def _create_rep_gen_set(self, n, p):
     """
     A helper function. Creates the gen_set for has_irred_rep().
     """
     import itertools
     alphabet = [_to_word(self.gen(i)) for i in range(self.ngens())]
     power_word = [alphabet[i]**n for i in range(self.ngens())]
     for i in range(1, p + 1):
         for words in itertools.product(alphabet, repeat=i):
             yield_word = True
             word = Word('')
             for w in words:
                 word = word * w
             rewrite = []
             empty_word = Word('')
             for rel in self._reduce:
                 if rel[0].is_factor(word):
                     yield_word = False
                     break
             if yield_word:
                 for pw in power_word:
                     if pw.is_factor(word):
                         yield_word = False
                         break
             if yield_word: yield word
Beispiel #6
0
    def subdivide(self, edge_list):
        """
          Subdvides each of the edges in ``edge_list`` into two edges.

          An edge may appear several time in the list: it will be
          subdivided as many times.  

          OUTPUT:

          A dictionnary that maps an old edge to a path in the new
          graph.

          """
        A = self._alphabet
        result_map = dict((e, Word([e])) for e in A)
        new_edges = A.add_new_letters(len(edge_list))
        new_vertices = self.new_vertices(len(edge_list))

        for i, e in enumerate(edge_list):
            ee = A.inverse_letter(e)
            ne = result_map[e][-1]
            v = new_vertices[i]
            vt = self.terminal_vertex(result_map[e][-1])
            f = new_edges[i][0]
            ff = new_edges[i][1]
            self.set_terminal_vertex(ne, v)
            self.add_edge(v, vt, [f, ff])
            result_map[e] = result_map[e] * Word([f])
            result_map[ee] = Word([ff]) * result_map[ee]
        return result_map
Beispiel #7
0
    def __iter__(self):
        """
        TESTS::

            sage: WeightedIntegerVectors(7, [2,2]).list()
            []
            sage: WeightedIntegerVectors(3, [2,1,1]).list()
            [[1, 0, 1], [1, 1, 0], [0, 0, 3], [0, 1, 2], [0, 2, 1], [0, 3, 0]]

        ::

            sage: ivw = [ WeightedIntegerVectors(k, [1,1,1]) for k in range(11) ]
            sage: iv  = [ IntegerVectors(k, 3) for k in range(11) ]
            sage: all( [ sorted(iv[k].list()) == sorted(ivw[k].list()) for k in range(11) ] )
            True

        ::

            sage: ivw = [ WeightedIntegerVectors(k, [2,3,7]) for k in range(11) ]
            sage: all( [ i.cardinality() == len(i.list()) for i in ivw] )
            True
        """
        if len(self._weights) == 0:
            if self._n == 0:
                yield []
            return

        perm = Word(self._weights).standard_permutation()
        l = [x for x in sorted(self._weights)]
        for x in self._recfun(self._n, l):
            yield perm.action(x)
Beispiel #8
0
    def rips_machine_moves(self,side=None,holes=None,orientation=None,verbose=False):
        r"""
        Return the list of possible moves of the Rips machine.

        A move is an automorphism of the free group. Assume that self
        is the convex core of an automorphism phi. Let psi be an
        automorphism given by ``self.rips_machine_moces(side=1)``,
        then ``ConvexCore(phi*psi)`` is obtained from ``self`` by a
        move of the Rips machine. On the other side: if ``psi`` is
        given by ``self.rips_machine_moces(side=0)``, then
        ``ConvexCore(psi.inverse()*phi)`` is given by a move of the
        Rips machine.

        INPUT:

        - `side` (default 0): side of Rips moves to find, either 0, 1
        or None for both sides.  
        
        OUPUT:

        - A list of free group automorphisms.

        """

        if holes is None:
            holes=self.rips_machine_holes(side=side,orientation=orientation,verbose=verbose and verbose>1 and verbose-1)

        result=[]        
        
        for i,hole in enumerate(holes):
            e,b,start_letters,end_letters=hole

            A=self.tree(side=b[1]).alphabet()

            hole_map=dict((a,Word([a])) for a in A.positive_letters())
                
            bb=A.inverse_letter(b[0])
            if bb in start_letters:
                if verbose:
                    print i,":",hole
                    print "surgery:",e[2],",",(bb,b[1])
                for x in end_letters:
                    if A.is_positive_letter(x):
                        hole_map[x]=Word([bb])*hole_map[x]
                    else:
                        xx=A.inverse_letter(x)
                        hole_map[xx]=hole_map[xx]*Word([b[0]])
            else:
                if verbose:
                    print i,":",hole
                    print "surgery:",e[2],",",b
                for x in start_letters:
                    if A.is_positive_letter(x):
                        hole_map[x]=Word([bb])*hole_map[x]
                    else:
                        xx=A.inverse_letter(x)
                        hole_map[xx]=hole_map[xx]*Word([b[0]])
            result.append(hole_map)    
            
        return result
    def list(self):
        """
        TESTS::
        
            sage: WeightedIntegerVectors(7, [2,2]).list()
            []
            sage: WeightedIntegerVectors(3, [2,1,1]).list()
            [[1, 0, 1], [1, 1, 0], [0, 0, 3], [0, 1, 2], [0, 2, 1], [0, 3, 0]]
        
        ::
        
            sage: ivw = [ WeightedIntegerVectors(k, [1,1,1]) for k in range(11) ]
            sage: iv  = [ IntegerVectors(k, 3) for k in range(11) ]
            sage: all( [ sorted(iv[k].list()) == sorted(ivw[k].list()) for k in range(11) ] )
            True
        
        ::
        
            sage: ivw = [ WeightedIntegerVectors(k, [2,3,7]) for k in range(11) ]
            sage: all( [ i.cardinality() == len(i.list()) for i in ivw] )
            True
        """
        if len(self.weight) == 0:
            if self.n == 0:
                return [[]]
            else:
                return []

        perm = Word(self.weight).standard_permutation()
        l = [x for x in sorted(self.weight)]
        return [perm.action(_) for _ in self._recfun(self.n, l)]
Beispiel #10
0
    def list(self):
        """
        TESTS::

            sage: WeightedIntegerVectors(7, [2,2]).list()
            []
            sage: WeightedIntegerVectors(3, [2,1,1]).list()
            [[1, 0, 1], [1, 1, 0], [0, 0, 3], [0, 1, 2], [0, 2, 1], [0, 3, 0]]

        ::

            sage: ivw = [ WeightedIntegerVectors(k, [1,1,1]) for k in range(11) ]
            sage: iv  = [ IntegerVectors(k, 3) for k in range(11) ]
            sage: all( [ sorted(iv[k].list()) == sorted(ivw[k].list()) for k in range(11) ] )
            True

        ::

            sage: ivw = [ WeightedIntegerVectors(k, [2,3,7]) for k in range(11) ]
            sage: all( [ i.cardinality() == len(i.list()) for i in ivw] )
            True
        """
        if len(self.weight) == 0:
            if self.n == 0:
                return [[]]
            else:
                return []

        perm = Word(self.weight).standard_permutation()
        l = [x for x in sorted(self.weight)]
        return [perm.action(_) for _ in self._recfun(self.n,l)]
Beispiel #11
0
    def blow_up_vertices(self, germ_components):
        """
        Blow-up ``self`` according to classes of germs given in
        ``germ_components``.

        INPUT:

        ``germ_components`` a list of classes of germs outgoing from a
        vertex.

        OUTPUT:
        
        A dictionnay that maps an old edge to the path in the new
        graph.
        """

        A = self.alphabet()

        result_map = dict((a, Word([a])) for a in A)

        new_vertices = self.new_vertices(len(germ_components))
        new_edges = A.add_new_letters(len(germ_components))

        for i, c in enumerate(germ_components):
            v0 = self.initial_vertex(c[0])
            vc = new_vertices[i]
            ec = new_edges[i]
            self.add_edge(v0, vc, ec)
            for a in c:
                self.set_initial_vertex(a, vc)
                result_map[a] = Word([ec[0]]) * result_map[a]
                aa = A.inverse_letter(a)
                result_map[aa] = result_map[aa] * Word([ec[1]])

        return result_map
Beispiel #12
0
def spin_rec(t, nexts, current, part, weight, length):
    """
    Routine used for constructing the spin polynomial.
    
    INPUT:
    
    
    -  ``weight`` - list of non-negative integers
    
    -  ``length`` - the length of the ribbons we're tiling
       with
    
    -  ``t`` - the variable
    
    
    EXAMPLES::
    
        sage: from sage.combinat.ribbon_tableau import spin_rec
        sage: sp = SkewPartition
        sage: t = ZZ['t'].gen()
        sage: spin_rec(t, [], [[[], [3, 3]]], sp([[2, 2, 2], []]), [2], 3) 
        [t^4]
        sage: spin_rec(t, [[0], [t^4]], [[[2, 1, 1, 1, 1], [0, 3]], [[2, 2, 2], [3, 0]]], sp([[2, 2, 2, 2, 1], []]), [2, 1], 3) 
        [t^5]
        sage: spin_rec(t, [], [[[], [3, 3, 0]]], sp([[3, 3], []]), [2], 3) 
        [t^2]
        sage: spin_rec(t, [[t^4], [t^3], [t^2]], [[[2, 2, 2], [0, 0, 3]], [[3, 2, 1], [0, 3, 0]], [[3, 3], [3, 0, 0]]], sp([[3, 3, 3], []]), [2, 1], 3) 
        [t^6 + t^4 + t^2]
        sage: spin_rec(t, [[t^5], [t^4], [t^6 + t^4 + t^2]], [[[2, 2, 2, 2, 1], [0, 0, 3]], [[3, 3, 1, 1, 1], [0, 3, 0]], [[3, 3, 3], [3, 0, 0]]], sp([[3, 3, 3, 2, 1], []]), [2, 1, 1], 3) 
        [2*t^7 + 2*t^5 + t^3]
    """
    from sage.combinat.words.word import Word
    R = ZZ['t']
    if current == []:
        return [R(0)]

    tmp = []
    partp = part[0].conjugate()

    #compute the contribution of the ribbons added at
    #the current node
    for perms in [current[i][1] for i in range(len(current))]:
        perm = [
            partp[i] + len(partp) - (i + 1) - perms[i]
            for i in range(len(partp))
        ]
        perm.reverse()
        perm = Word(perm).standard_permutation()
        tmp.append((weight[-1] * (length - 1) - perm.number_of_inversions()))

    if nexts != []:
        return [
            sum([
                sum([t**tmp[i] * nexts[i][j] for j in range(len(nexts[i]))])
                for i in range(len(tmp))
            ])
        ]
    else:
        return [sum([t**tmp[i] for i in range(len(tmp))])]
Beispiel #13
0
    def splitting(i, A):
        """
        The ``MarkedMetricGraph`` that corresponds to the splitting
        ``F(A)=F(A[:i])*F(A[i:])``.

        This is a graph with two vertices linked by an edge e and a
        loop for each letter in A. Letters in A[:i] are attached to
        the first vertex while letters in A[:i] are attached to the
        second vertex.

        All loops have length 0, the splitting edge ``e`` has length 1.

        INPUT:

        - ``i`` -- integer correspond to the splitting index
        - ``A`` -- an alphabet

        OUTPUT:

        The ``MarkedMetricGraph`` corresponding to splitting.

        EXAMPLES::

            sage: from train_track import *
            sage: from train_track.marked_graph import  MarkedMetricGraph
            sage: A = AlphabetWithInverses(5)
            sage: print(MarkedMetricGraph.splitting(2,A))
            Marked graph: a: 0->0, b: 0->0, c: 1->1, d: 1->1, e:
            1->1, f: 0->1
            Marking: a->a, b->b, c->fcF, d->fdF, e->feF
            Length: a:0, b:0, c:0, d:0, e:0, f:1
        """

        graph = dict()
        length = dict()
        marking = dict()

        B = A.copy()
        [e, ee] = B.add_new_letter()

        for j in range(i):
            a = A[j]
            graph[a] = (0, 0)
            length[a] = 0
            marking[a] = Word([a])

        for j in range(i, len(A)):
            a = A[j]
            graph[a] = (1, 1)
            length[a] = 0
            marking[a] = Word([e, a, ee])

        graph[e] = (0, 1)
        length[e] = 1

        return MarkedMetricGraph(graph, marking, length, B, A)
Beispiel #14
0
def spin_rec(t, nexts, current, part, weight, length):
    """
    Routine used for constructing the spin polynomial.
    
    INPUT:
    
    
    -  ``weight`` - list of non-negative integers
    
    -  ``length`` - the length of the ribbons we're tiling
       with
    
    -  ``t`` - the variable
    
    
    EXAMPLES::
    
        sage: from sage.combinat.ribbon_tableau import spin_rec
        sage: sp = SkewPartition
        sage: t = ZZ['t'].gen()
        sage: spin_rec(t, [], [[[], [3, 3]]], sp([[2, 2, 2], []]), [2], 3) 
        [t^4]
        sage: spin_rec(t, [[0], [t^4]], [[[2, 1, 1, 1, 1], [0, 3]], [[2, 2, 2], [3, 0]]], sp([[2, 2, 2, 2, 1], []]), [2, 1], 3) 
        [t^5]
        sage: spin_rec(t, [], [[[], [3, 3, 0]]], sp([[3, 3], []]), [2], 3) 
        [t^2]
        sage: spin_rec(t, [[t^4], [t^3], [t^2]], [[[2, 2, 2], [0, 0, 3]], [[3, 2, 1], [0, 3, 0]], [[3, 3], [3, 0, 0]]], sp([[3, 3, 3], []]), [2, 1], 3) 
        [t^6 + t^4 + t^2]
        sage: spin_rec(t, [[t^5], [t^4], [t^6 + t^4 + t^2]], [[[2, 2, 2, 2, 1], [0, 0, 3]], [[3, 3, 1, 1, 1], [0, 3, 0]], [[3, 3, 3], [3, 0, 0]]], sp([[3, 3, 3, 2, 1], []]), [2, 1, 1], 3) 
        [2*t^7 + 2*t^5 + t^3]
    """
    from sage.combinat.words.word import Word
    R = ZZ['t']
    if current == []:
        return [R(0)]

    tmp = []
    partp = part[0].conjugate()

    #compute the contribution of the ribbons added at
    #the current node
    for perms in [current[i][1] for i in range(len(current))]:
        perm =  [partp[i] + len(partp)-(i+1)-perms[i] for i in range(len(partp))]
        perm.reverse()
        perm = Word(perm).standard_permutation()
        tmp.append( (weight[-1]*(length-1)-perm.number_of_inversions()) )

    if nexts != []:
        return [sum([sum([t**tmp[i]*nexts[i][j] for j in range(len(nexts[i]))]) for i in range(len(tmp))])]
    else:
        return [sum([t**tmp[i] for i in range(len(tmp))])]
Beispiel #15
0
        def succ_product_on_basis(self, x, y):
            r"""
            Return the `\succ` product of two permutations.

            This is the shifted shuffle of `x` and `y` with the additional
            condition that the first letter of the result comes from `y`.

            The usual symbol for this operation is `\succ`.

            .. SEEALSO::

                - :meth:`product_on_basis`, :meth:`prec_product_on_basis`

            EXAMPLES::

                sage: A = algebras.FQSym(QQ).F()
                sage: x = Permutation([1,2])
                sage: A.succ_product_on_basis(x, x)
                F[3, 1, 2, 4] + F[3, 1, 4, 2] + F[3, 4, 1, 2]
                sage: y = Permutation([])
                sage: A.succ_product_on_basis(x, y) == 0
                True
                sage: A.succ_product_on_basis(y, x) == A(x)
                True

            TESTS::

                sage: u = A.one().support()[0]
                sage: A.succ_product_on_basis(u, u)
                Traceback (most recent call last):
                ...
                ValueError: products | < | and | > | are not defined
            """
            if not y:
                if not x:
                    raise ValueError(
                        "products | < | and | > | are not defined")
                else:
                    return self.zero()
            basis = self.basis()
            if not x:
                return basis[y]
            K = basis.keys()
            n = len(x)
            shy = Word([a + n for a in y])
            shy0 = shy[0]
            return self.sum(basis[K([shy0] + list(u))]
                            for u in Word(x).shuffle(Word(shy[1:])))
Beispiel #16
0
    def subdivide(self, edge_list):
        """
        Subdvides each of the edges in ``edge_list`` into two edges.

        An edge may appear several time in the list: it will be
        subdivided as many times.

        INPUT:

        - ``edge_list`` -- list of edges

        OUTPUT:

        A dictionnary that maps an old edge to a path in the new
        graph.

        EXAMPLES::

            sage: from train_track.inverse_graph import GraphWithInverses
            sage: G = GraphWithInverses([[0,0,'a'],[0,1,'b'],[1,1,'c']])
            sage: G.subdivide(['a','c'])
            {'A': word: DA,
             'B': word: B,
             'C': word: EC,
             'a': word: ad,
             'b': word: b,
             'c': word: ce}
            sage: print(G)
            a: 0->2, b: 0->1, c: 1->3, d: 2->0, e: 3->1
        """

        A = self._alphabet
        result_map = dict((e, Word([e])) for e in A)
        new_edges = A.add_new_letters(len(edge_list))
        new_vertices = self.new_vertices(len(edge_list))

        for i, e in enumerate(edge_list):
            ee = A.inverse_letter(e)
            ne = result_map[e][-1]
            v = new_vertices[i]
            vt = self.terminal_vertex(result_map[e][-1])
            f = new_edges[i][0]
            ff = new_edges[i][1]
            self.set_terminal_vertex(ne, v)
            self.add_edge(v, vt, [f, ff])
            result_map[e] = result_map[e] * Word([f])
            result_map[ee] = Word([ff]) * result_map[ee]
        return result_map
def reverse_sorting_permutation(
        t):  # TODO: put "stable sorting" as keyword somewhere
    r"""
    Return a permutation `p` such that  is decreasing

    INPUT:
    - `t` -- a list/tuple/... of numbers

    OUTPUT:

    a minimal permutation `p` such that `w \circ p` is sorted decreasingly

    EXAMPLES::

        sage: t = [3, 3, 1, 2]
        sage: s = reverse_sorting_permutation(t); s
        [1, 2, 4, 3]
        sage: [t[s[i]-1] for i in range(len(t))]
        [3, 3, 2, 1]

        sage: t = [4, 2, 3, 2, 1, 3]
        sage: s = reverse_sorting_permutation(t); s
        [1, 3, 6, 2, 4, 5]
        sage: [t[s[i]-1] for i in range(len(t))]
        [4, 3, 3, 2, 2, 1]
    """
    return ~(Word([-i for i in t]).standard_permutation())
Beispiel #18
0
    def to_word(self, alphabet=[1, 2, 3]):
        r"""
        Return the billiard word.

        INPUT:

        - ``alphabet`` - list

        EXAMPLES::

            sage: from slabbe import BilliardCube
            sage: b = BilliardCube((1,pi,sqrt(2)))
            sage: b.to_word()
            word: 2321232212322312232123221322231223212322...

        ::

            sage: B = BilliardCube((sqrt(3),sqrt(5),sqrt(7)))
            sage: B.to_word()
            word: 3213213231232133213213231232132313231232...

        """
        steps = map(vector, ((1, 0, 0), (0, 1, 0), (0, 0, 1)))
        for step in steps:
            step.set_immutable()
        coding = dict(zip(steps, alphabet))
        it = (coding[step] for step in self.step_iterator())
        #WP = WordPaths(alphabet, [(1,0,0),(0,1,0),(0,0,1)])
        return Word(it, alphabet=alphabet)
Beispiel #19
0
    def rose_marked_graph(alphabet):
        """
        The rose on ``alphabet`` marked with the identity.

        INPUT:

        - ``alphabet`` -- an alphabet

        OUTPUT:

        The rose on ``alphabet`` marked with the identity.

        EXAMPLES::

            sage: from train_track import *
            sage: from train_track.inverse_graph import GraphWithInverses
            sage: from train_track.marked_graph import MarkedGraph
            sage: print(MarkedGraph.rose_marked_graph(AlphabetWithInverses(2)))
            Marked graph: a: 0->0, b: 0->0
            Marking: a->a, b->b
        """

        marking = dict((a, Word([a])) for a in alphabet.positive_letters())
        return MarkedGraph(graph=GraphWithInverses.rose_graph(alphabet),
                           marking=marking,
                           marking_alphabet=alphabet)
Beispiel #20
0
    def __iter__(self):
        """
        TESTS::

            sage: WeightedIntegerVectors(7, [2,2]).list()
            []
            sage: WeightedIntegerVectors(3, [2,1,1]).list()
            [[1, 0, 1], [1, 1, 0], [0, 0, 3], [0, 1, 2], [0, 2, 1], [0, 3, 0]]

        ::

            sage: ivw = [ WeightedIntegerVectors(k, [1,1,1]) for k in range(11) ]
            sage: iv  = [ IntegerVectors(k, 3) for k in range(11) ]
            sage: all(sorted(map(list, iv[k])) == sorted(map(list, ivw[k])) for k in range(11))
            True

        ::

            sage: ivw = [ WeightedIntegerVectors(k, [2,3,7]) for k in range(11) ]
            sage: all(i.cardinality() == len(i.list()) for i in ivw)
            True
        """
        if not self._weights:
            if self._n == 0:
                yield self.element_class(self, [])
            return

        perm = Word(self._weights).standard_permutation()
        perm = [len(self._weights) - i for i in perm]
        l = [x for x in sorted(self._weights, reverse=True)]
        for x in iterator_fast(self._n, l):
            yield self.element_class(self, [x[i] for i in perm])
    def to_labelling_permutation(self):
        r"""
        Returns the labelling of the support Dyck path of the parking function.

        INPUT:

        - ``self`` -- parking function word

        OUTPUT:

        - returns the labelling of the Dyck path

        EXAMPLES::

            sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
            sage: PF.to_labelling_permutation()
            [2, 6, 4, 5, 3, 7, 1]

        ::

            sage: ParkingFunction([3,1,1,4]).to_labelling_permutation()
            [2, 3, 1, 4]
            sage: ParkingFunction([4,1,1,1]).to_labelling_permutation()
            [2, 3, 4, 1]
            sage: ParkingFunction([2,1,4,1]).to_labelling_permutation()
            [2, 4, 1, 3]
        """
        from sage.combinat.words.word import Word
        return Word(self).standard_permutation().inverse()
Beispiel #22
0
    def __iter__(self):
        """
        TESTS::

            sage: [ p for p in OrderedSetPartitions([1,2,3,4], [2,1,1]) ]
            [[{1, 2}, {3}, {4}],
             [{1, 2}, {4}, {3}],
             [{1, 3}, {2}, {4}],
             [{1, 4}, {2}, {3}],
             [{1, 3}, {4}, {2}],
             [{1, 4}, {3}, {2}],
             [{2, 3}, {1}, {4}],
             [{2, 4}, {1}, {3}],
             [{3, 4}, {1}, {2}],
             [{2, 3}, {4}, {1}],
             [{2, 4}, {3}, {1}],
             [{3, 4}, {2}, {1}]]
        """
        comp = self.c
        lset = [x for x in self._set]
        l = len(self.c)
        dcomp = [-1] + comp.descents(final_descent=True)

        p = []
        for j in range(l):
            p += [j + 1] * comp[j]

        for x in permutation.Permutations(p):
            res = permutation.Permutation(range(
                1, len(lset))) * Word(x).standard_permutation().inverse()
            res = [lset[x - 1] for x in res]
            yield self.element_class(
                self,
                [Set(res[dcomp[i] + 1:dcomp[i + 1] + 1]) for i in range(l)])
Beispiel #23
0
def discrete_curve(nb_equipes,
                   max_points=100,
                   K=1,
                   R=2,
                   base=2,
                   verbose=False):
    r"""
    INPUT:

    - ``nb_equipes`` -- integer
    - ``max_points`` -- integer
    - ``K`` -- the value at ``p = nb_equipes``
    - ``R`` -- real (default: ``2``), curve parameter
    - ``base`` -- 2
    - ``verbose`` - bool 

    EXEMPLES::
        
        sage: from slabbe.ranking_scale import discrete_curve
        sage: A = discrete_curve(64, 100,verbose=True)
        First difference sequence is
        [1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 1,
        2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 2, 3, 3, 3, 4, 4, 4]

    ::

        sage: A = discrete_curve(64, 100)
        sage: B = discrete_curve(32, 50)
        sage: C = discrete_curve(16, 25)

    ::

        sage: A
        [100, 96, 92, 88, 85, 82, 79, 77, 74, 71, 69, 67, 64, 62, 60, 58,
        56, 54, 52, 50, 49, 47, 45, 44, 42, 41, 39, 38, 36, 35, 33, 32, 31,
        29, 28, 27, 26, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12,
        11, 10, 9, 8, 8, 7, 6, 5, 5, 4, 3, 2, 2, 1]
        sage: B
        [50, 46, 43, 40, 37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17,
        16, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1]
        sage: C
        [25, 22, 19, 17, 15, 13, 11, 9, 8, 7, 6, 5, 4, 3, 2, 1]

    ::

        sage: A = discrete_curve(64+2, 100) #Movember, Bye Bye, Cdf, MA
        sage: B = discrete_curve(32+2, 70)  # la flotte
        sage: C = discrete_curve(16+2, 40) # october fest, funenuf, la viree
    """
    from sage.misc.functional import round
    from sage.rings.integer_ring import ZZ
    from sage.combinat.words.word import Word
    fn_normalise = curve(nb_equipes, max_points, K=K, R=R, base=base)
    L = [ZZ(round(fn_normalise(p=i))) for i in range(1, nb_equipes + 1)]
    if verbose:
        print "First difference sequence is"
        print list(Word(L).reversal().finite_differences())
    return L
    def lie_polynomial(self, w):
        """
        Return the Lie polynomial associated to the Lyndon word ``w``. If
        ``w`` is not Lyndon, then return the product of Lie polynomials of the
        Lyndon factorization of ``w``.

        INPUT:

        - ``w`` -- a word or an element of the free monoid

        EXAMPLES::

            sage: F = FreeAlgebra(QQ, 3, 'x,y,z')
            sage: M.<x,y,z> = FreeMonoid(3)
            sage: F.lie_polynomial(x*y)
            x*y - y*x
            sage: F.lie_polynomial(y*x)
            y*x
            sage: F.lie_polynomial(x^2*y*x)
            x^2*y*x - x*y*x^2
            sage: F.lie_polynomial(y*z*x*z*x*z)
            y*z*x*z*x*z - y*z*x*z^2*x - y*z^2*x^2*z + y*z^2*x*z*x
             - z*y*x*z*x*z + z*y*x*z^2*x + z*y*z*x^2*z - z*y*z*x*z*x

        TESTS:

        We test some corner cases and alternative inputs::

            sage: F.lie_polynomial(Word('xy'))
            x*y - y*x
            sage: F.lie_polynomial('xy')
            x*y - y*x
            sage: F.lie_polynomial(M.one())
            1
            sage: F.lie_polynomial(Word([]))
            1
            sage: F.lie_polynomial('')
            1
        """
        if not w:
            return self.one()
        M = self._basis_keys

        if len(w) == 1:
            return self(M(w))

        ret = self.one()
        # We have to be careful about order here.
        # Since the Lyndon factors appear from left to right
        #   we must multiply from left to right as well.
        for factor in Word(w).lyndon_factorization():
            if len(factor) == 1:
                ret = ret * self(M(factor))
                continue
            x,y = factor.standard_factorization()
            x = M(x)
            y = M(y)
            ret = ret * (self(x * y) - self(y * x))
        return ret
Beispiel #25
0
    def __contains__(self, x):
        """
        EXAMPLES::

            sage: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2
            sage: W = Words("abcd")
            sage: w = W("ab")
            sage: u = W("cd")
            sage: S = ShuffleProduct_w1w2(w,u)
            sage: w*u in S
            True
            sage: all(w.is_subword_of(x) for x in S)
            True
            sage: w in S
            False

        We check that :trac:`14121` is solved::

            sage: w = W('ab')
            sage: x = W('ac')
            sage: x*w in w.shuffle(x)
            True
        """
        from sage.combinat.words.word import Word
        if not isinstance(x, Word_class):
            return False
        if x.length() != self._w1.length() + self._w2.length():
            return False
        w1 = list(self._w1)
        w2 = list(self._w2)
        wx = list(x)
        for _ in range(len(wx)):
            try:
                letter = wx.pop(0)
            except IndexError:
                return False
            if w1 and w2 and letter == w1[0] == w2[0]:
                return (Word(wx) in self._w1[1:].shuffle(self._w2) or
                        Word(wx) in self._w1.shuffle(self._w2[1:]))
            if w1 and letter == w1[0]:
                w1.pop(0)
            elif w2 and letter == w2[0]:
                w2.pop(0)
            else:
                return False
        return not wx
Beispiel #26
0
    def spanning_tree(self, verbose=False):
        """
        Return a spanning tree of ``self``.

        The origin vertex of the spanning tree is the initial vertex
        of the edge labeled by ``self._alphabet[0]``.

        OUPUT:

        a dictionnary that maps each vertex to an edge-path
        from the origin vertex.

        .. SEEALSO::

            :meth:`maximal_tree()` that returns a list of edges
            of a spanning tree.

        .. WARNING::

            ``self`` must be connected.

        EXAMPLES::

            sage: from train_track.inverse_graph import GraphWithInverses
            sage: G = GraphWithInverses([[0,0,'a'],[0,1,'b'],[1,0,'c']])
            sage: G.spanning_tree()
            {0: word: , 1: word: b}
        """

        A = self._alphabet
        tree = {self.initial_vertex(A[0]): Word()}

        done = False
        while not done:
            done = True
            for a in A.positive_letters():
                vi = self.initial_vertex(a)
                vt = self.terminal_vertex(a)
                if vi in tree and vt not in tree:
                    tree[vt] = self.reduce_path(tree[vi] * Word([a]))
                    done = False
                elif vt in tree and vi not in tree:
                    tree[vi] = self.reduce_path(tree[vt] *
                                                Word([A.inverse_letter(a)]))
                    done = False
        return tree
Beispiel #27
0
    def contract_forest(self, forest):
        """
          Contract the forest.

          Each tree of the forest is contracted to the initial vertex of its first
          edge.

          INPUT:

          ``forest`` is a list of disjoint subtrees each given as
          lists of edges.

          OUTPUT:

          A dictionnary that maps an old edge to its image in the new
          graph.
          """
        A = self._alphabet

        edge_map = dict((e, Word([e])) for e in A)
        vertex_map = {}

        for tree in forest:
            first = True
            for e in tree:
                if first:
                    vtree = self.initial_vertex(e)
                    first = False
                vertex_map[self.initial_vertex(e)] = vtree
                vertex_map[self.terminal_vertex(e)] = vtree
                edge_map[e] = Word([])
                edge_map[A.inverse_letter(e)] = Word([])
                self.remove_edge(e)

        for e in A:
            v = self.initial_vertex(e)
            if v in vertex_map and v != vertex_map[v]:
                self.set_initial_vertex(e, vertex_map[self.initial_vertex(e)])

        for v in vertex_map:
            if v != vertex_map[v]:
                self.remove_vertex(v)

        return edge_map
Beispiel #28
0
    def blow_up_vertices(self, germ_components):
        """
        Blow-up ``self`` according to classes of germs given in
        ``germ_components``.

        INPUT:

        - ``germ_components`` -- a list of classes of germs outgoing
          from a vertex

        OUTPUT:

        A dictionnary that maps an old edge to the path in the new graph.

        EXAMPLES::

            sage: from train_track import *
            sage: from train_track.inverse_graph import GraphWithInverses
            sage: G = GraphWithInverses.rose_graph(AlphabetWithInverses(2))
            sage: G.blow_up_vertices([['a','A'],['b'],['B']])
            {'A': word: cAC, 'B': word: eBD, 'a': word: caC, 'b': word: dbE}
            sage: print(G)
            a: 1->1, b: 2->3, c: 0->1, d: 0->2, e: 0->3
        """

        A = self.alphabet()

        result_map = dict((a, Word([a])) for a in A)

        new_vertices = self.new_vertices(len(germ_components))
        new_edges = A.add_new_letters(len(germ_components))

        for i, c in enumerate(germ_components):
            v0 = self.initial_vertex(c[0])
            vc = new_vertices[i]
            ec = new_edges[i]
            self.add_edge(v0, vc, ec)
            for a in c:
                self.set_initial_vertex(a, vc)
                result_map[a] = Word([ec[0]]) * result_map[a]
                aa = A.inverse_letter(a)
                result_map[aa] = result_map[aa] * Word([ec[1]])

        return result_map
Beispiel #29
0
    def subdivide_domain(self, e):
        """
        Subdivide an edge in the domain graph. 

        The edge ``e`` is subdivided into ``l`` edges where ``l`` is
        the length of the image of ``e`` by ``self``.

        Update the edge map of ``self``.

        Intended to be used by Stalling's folding algorithm to get an
        immersion.

        SEE ALSO::

        GraphWithInverses.subdivide_edge()

        """
        G = self.domain()
        A = G.alphabet()
        result_map = dict((a, Word([a])) for a in A)
        w = self.image(e)
        new_edges = A.add_new_letters(len(w) - 1)
        new_vertices = G.new_vertices(len(w) - 1)
        d = {(a, self.image(a)) for a in A.positive_letters()}
        for i, a in enumerate(new_edges):
            v = new_vertices[i]
            if i == 0:
                vi = G.initial_vertex(e)
                vt = G.terminal_vertex(e)
                f = new_edges[i][0]
                ee = A.inverse_letter(e)
                ff = new_edges[i][1]
                G.set_terminal_vertex(e, v)
                G.add_edge(v, vt, [f, ff])
                result_map[e] = result_map[e] * Word([f])
                result_map[ee] = Word([ff]) * result_map[ee]
                d[a[0]] = w[i + 1]
            else:
                vi = self._domain.initial_vertex(new_edges[i - 1][0])
                vt = self._domain.terminal_vertex(new_edges[i - 1][0])
                f = new_edges[i][0]
                #ee=A.inverse_letter(e) #already done
                ff = new_edges[i][1]
                self._domain.set_terminal_vertex(new_edges[i - 1][0], v)
                self._domain.add_edge(v, vt, [f, ff])
                result_map[e] = result_map[e] * Word([f])
                result_map[ee] = Word([ff]) * result_map[ee]
                d[a[0]] = w[i + 1]

        # updating self.edge_map after subdivision
        if A.is_positive_letter(e):
            d[e] = Word([self.image(e)[0]])
        else:
            d[ee] = Word([self.image(ee)[-1]])

        self.set_edge_map(d)

        return result_map
Beispiel #30
0
    def skeleton_cycles(self):
        r"""
        EXAMPLES::

            sage: from slabbe import DoubleRootedTree
            sage: edges = [(0,5),(1,2),(2,6),(3,2),(4,1),(5,7),(7,1),(8,2),(9,4)]
            sage: D = DoubleRootedTree(edges, 6, 0)
            sage: D.skeleton()
            [0, 5, 7, 1, 2, 6]
            sage: D.skeleton_cycles()
            [(0,), (1, 5), (2, 7, 6)]
        """
        skeleton = self.skeleton()
        sorted_skeleton = sorted(skeleton)
        w = Word(skeleton)
        cycles_standard = w.standard_permutation().to_cycles()
        cycles = []
        for cycle_standard in cycles_standard:
            t = tuple(sorted_skeleton[c-1] for c in cycle_standard)
            cycles.append(t)
        return cycles
Beispiel #31
0
def is_littlewood_richardson(t, heights):
    """
    Return whether semistandard tableau ``t`` is Littleword-Richardson
    with respect to ``heights``.

    A tableau is Littlewood-Richardson with respect to ``heights`` given
    by `(h_1, h_2, \ldots)` if each subtableau with respect to the
    alphabets `\{1, 2, \ldots, h_1\}`, `\{h_1+1, \ldots, h_1+h_2\}`,
    etc. is Yamanouchi.

    EXAMPLES::

        sage: from sage.combinat.lr_tableau import is_littlewood_richardson
        sage: t = Tableau([[1,1,2,3,4],[2,3,3],[3]])
        sage: is_littlewood_richardson(t,[2,2])
        False
        sage: t = Tableau([[1,1,3],[2,3],[4,4]])
        sage: is_littlewood_richardson(t,[2,2])
        True
        sage: t = Tableau([[7],[8]])
        sage: is_littlewood_richardson(t,[2,3,3])
        False
        sage: is_littlewood_richardson([[2],[3]],[3,3])
        False
    """
    from sage.combinat.words.word import Word
    partial = [
        sum(heights[i] for i in range(j)) for j in range(len(heights) + 1)
    ]
    try:
        w = t.to_word()
    except AttributeError:  # Not an instance of Tableau
        w = sum(reversed(t), [])
    for i in range(len(heights)):
        subword = Word([j for j in w if partial[i] + 1 <= j <= partial[i + 1]],
                       alphabet=list(range(partial[i] + 1,
                                           partial[i + 1] + 1)))
        if not subword.is_yamanouchi():
            return False
    return True
    def reading_word(self):
        """
        Return the reading word of ``self``, obtained by reading the boxes
        entries of self from right to left, starting in the upper right.

        EXAMPLES::

            sage: a = AugmentedLatticeDiagramFilling([[1,6],[2],[3,4,2],[],[],[5,5]])
            sage: a.reading_word()
            word: 25465321
        """
        w = [self[i, j] for i, j in self.reading_order() if j > 0]
        return Word(w)
Beispiel #33
0
    def counit(self, S):
        """
        Return the counit of ``S``.

        EXAMPLES::

            sage: F = ShuffleAlgebra(QQ,'ab')
            sage: S = F.an_element(); S
            B[word: ] + 2*B[word: a] + 3*B[word: b] + B[word: bab]
            sage: F.counit(S)
            1
        """
        return S.monomial_coefficients().get(Word(), 0)
Beispiel #34
0
def is_littlewood_richardson(t, heights):
    r"""
    Return whether semistandard tableau ``t`` is Littleword-Richardson
    with respect to ``heights``.

    A tableau is Littlewood-Richardson with respect to ``heights`` given
    by `(h_1, h_2, \ldots)` if each subtableau with respect to the
    alphabets `\{1, 2, \ldots, h_1\}`, `\{h_1+1, \ldots, h_1+h_2\}`,
    etc. is Yamanouchi.

    EXAMPLES::

        sage: from sage.combinat.lr_tableau import is_littlewood_richardson
        sage: t = Tableau([[1,1,2,3,4],[2,3,3],[3]])
        sage: is_littlewood_richardson(t,[2,2])
        False
        sage: t = Tableau([[1,1,3],[2,3],[4,4]])
        sage: is_littlewood_richardson(t,[2,2])
        True
        sage: t = Tableau([[7],[8]])
        sage: is_littlewood_richardson(t,[2,3,3])
        False
        sage: is_littlewood_richardson([[2],[3]],[3,3])
        False
    """
    from sage.combinat.words.word import Word
    partial = [sum(heights[i] for i in range(j)) for j in range(len(heights)+1)]
    try:
        w = t.to_word()
    except AttributeError:  # Not an instance of Tableau
        w = sum(reversed(t), [])
    for i in range(len(heights)):
        subword = Word([j for j in w if partial[i]+1 <= j <= partial[i+1]],
                       alphabet=list(range(partial[i]+1,partial[i+1]+1)))
        if not subword.is_yamanouchi():
            return False
    return True