Esempio n. 1
0
def _digraph_mutate( dg, k, n, m ):
    """
    Returns a digraph obtained from dg with n+m vertices by mutating at vertex k.

    INPUT:

    - ``dg`` -- a digraph with integral edge labels with ``n+m`` vertices
    - ``k`` -- the vertex at which ``dg`` is mutated

    EXAMPLES::

        sage: from sage.combinat.cluster_algebra_quiver.mutation_class import _digraph_mutate
        sage: dg = ClusterQuiver(['A',4]).digraph()
        sage: dg.edges()
        [(0, 1, (1, -1)), (2, 1, (1, -1)), (2, 3, (1, -1))]
        sage: _digraph_mutate(dg,2,4,0).edges()
        [(0, 1, (1, -1)), (1, 2, (1, -1)), (3, 2, (1, -1))]
    """
    edges = dict( ((v1,v2),label) for v1,v2,label in dg._backend.iterator_in_edges(dg,True) )
    in_edges = [ (v1,v2,edges[(v1,v2)]) for (v1,v2) in edges if v2 == k ]
    out_edges = [ (v1,v2,edges[(v1,v2)]) for (v1,v2) in edges if v1 == k ]
    in_edges_new = [ (v2,v1,(-label[1],-label[0])) for (v1,v2,label) in in_edges ]
    out_edges_new = [ (v2,v1,(-label[1],-label[0])) for (v1,v2,label) in out_edges ]
    diag_edges_new = []
    diag_edges_del = []

    for (v1,v2,label1) in in_edges:
        for (w1,w2,label2) in out_edges:
            l11,l12 = label1
            l21,l22 = label2
            if (v1,w2) in edges:
                diag_edges_del.append( (v1,w2,edges[(v1,w2)]) )
                a,b = edges[(v1,w2)]
                a,b = a+l11*l21, b-l12*l22
                diag_edges_new.append( (v1,w2,(a,b)) )
            elif (w2,v1) in edges:
                diag_edges_del.append( (w2,v1,edges[(w2,v1)]) )
                a,b = edges[(w2,v1)]
                a,b = b+l11*l21, a-l12*l22
                if a<0:
                    diag_edges_new.append( (w2,v1,(b,a)) )
                elif a>0:
                    diag_edges_new.append( (v1,w2,(a,b)) )
            else:
                a,b = l11*l21,-l12*l22
                diag_edges_new.append( (v1,w2,(a,b)) )

    del_edges = in_edges + out_edges + diag_edges_del
    new_edges = in_edges_new + out_edges_new + diag_edges_new
    new_edges += [ (v1,v2,edges[(v1,v2)]) for (v1,v2) in edges if not (v1,v2,edges[(v1,v2)]) in del_edges ]

    dg_new = DiGraph()
    for v1,v2,label in new_edges:
        dg_new._backend.add_edge(v1,v2,label,True)
    if dg_new.order() < n+m:
        dg_new_vertices = [ v for v in dg_new ]
        for i in [ v for v in dg if v not in dg_new_vertices ]:
            dg_new.add_vertex(i)

    return dg_new
Esempio n. 2
0
    def plot(self,
             label_elements=True,
             element_labels=None,
             label_font_size=12,
             label_font_color='black',
             layout="acyclic",
             **kwds):
        """
        Returns a Graphics object corresponding to the Hasse diagram.
        
        EXAMPLES::
        
            sage: uc = [[2,3], [], [1], [1], [1], [3,4]]
            sage: elm_lbls = Permutations(3).list()
            sage: P = Poset(uc,elm_lbls)
            sage: H = P._hasse_diagram
            sage: levels = H.level_sets()
            sage: heights = dict([[i, levels[i]] for i in range(len(levels))])
            sage: type(H.plot(label_elements=True))
            <class 'sage.plot.graphics.Graphics'>
        
        ::
        
            sage: P = Posets.SymmetricGroupBruhatIntervalPoset([0,1,2,3], [2,3,0,1])
            sage: P._hasse_diagram.plot()
        """
        # Set element_labels to default to the vertex set.
        if element_labels is None:
            element_labels = range(self.num_verts())

        # Create the underlying graph.
        graph = DiGraph(self)
        graph.relabel(element_labels)

        return graph.plot(layout=layout, **kwds)
Esempio n. 3
0
    def plot(self, label_elements=True, element_labels=None,
            label_font_size=12,label_font_color='black', layout = "acyclic", **kwds):
        """
        Returns a Graphics object corresponding to the Hasse diagram.
        
        EXAMPLES::
        
            sage: uc = [[2,3], [], [1], [1], [1], [3,4]]
            sage: elm_lbls = Permutations(3).list()
            sage: P = Poset(uc,elm_lbls)
            sage: H = P._hasse_diagram
            sage: levels = H.level_sets()
            sage: heights = dict([[i, levels[i]] for i in range(len(levels))])
            sage: type(H.plot(label_elements=True))
            <class 'sage.plot.graphics.Graphics'>
        
        ::
        
            sage: P = Posets.SymmetricGroupBruhatIntervalPoset([0,1,2,3], [2,3,0,1])
            sage: P._hasse_diagram.plot()
        """
        # Set element_labels to default to the vertex set.
        if element_labels is None:
            element_labels = range(self.num_verts())

        # Create the underlying graph.
        graph = DiGraph(self)
        graph.relabel(element_labels)

        return graph.plot(layout = layout, **kwds)
Esempio n. 4
0
    def to_digraph(self, word_labels=False):
        r"""
        Returns a ``DiGraph`` object of the transition graph of the suffix tree.

        INPUT:

        -  ``word_labels`` - boolean (defaut: ``False``) if ``False``, labels 
           the edges by pairs `(i, j)`; if ``True``, labels the edges by 
           ``word[i:j]``.

        EXAMPLES::

            sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree
            sage: W = Words([0,1,2])
            sage: t = ImplicitSuffixTree(W([0,1,0,1,2]))
            sage: t.to_digraph()
            Digraph on 8 vertices
        """
        if self._letters == []:
            d = {0: {}}
            return DiGraph(d)
        d = self.transition_function_dictionary()
        for u in d:
            for (v, (i, j)) in d[u].iteritems():
                if word_labels:
                    d[u][v] = self._word[i:j]
                elif j == None:
                    d[u][v] = (i, len(self._letters))
        return DiGraph(d)
Esempio n. 5
0
def _matrix_to_digraph( M ):
    """
    Returns the digraph obtained from the matrix ``M``.
    In order to generate a quiver, we assume that ``M`` is skew-symmetrizable.

    EXAMPLES::

        sage: from sage.combinat.cluster_algebra_quiver.mutation_class import _matrix_to_digraph
        sage: _matrix_to_digraph(matrix(3,[0,1,0,-1,0,-1,0,1,0]))
        Digraph on 3 vertices
    """
    n = M.ncols()

    dg = DiGraph(sparse=True)
    for i,j in M.nonzero_positions():
        if i >= n: a,b = M[i,j],-M[i,j]
        else: a,b = M[i,j],M[j,i]
        if a > 0:
            dg._backend.add_edge(i,j,(a,b),True)
        elif i >= n:
            dg._backend.add_edge(j,i,(-a,-b),True)
    if dg.order() < M.nrows():
        for i in [ index for index in xrange(M.nrows()) if index not in dg ]:
            dg.add_vertex(i)
    return dg
Esempio n. 6
0
    def __init__(self):
        """
        EXAMPLES::

            sage: C = sage.categories.examples.crystals.NaiveCrystal()
            sage: C == Crystals().example(choice='naive')
            True
        """
        Parent.__init__(self, category = ClassicalCrystals())
        self.n = 2
        self._cartan_type = CartanType(['A',2])
        self.G = DiGraph(5)
        self.G.add_edges([ [0,1,1], [1,2,1], [2,3,1], [3,5,1],  [0,4,2], [4,5,2] ])
        self.module_generators = [ self(0) ]
Esempio n. 7
0
 def add_edge(self, i, j, label=1):
     """
     EXAMPLES::
     
         sage: from sage.combinat.root_system.dynkin_diagram import DynkinDiagram_class
         sage: d = DynkinDiagram_class(CartanType(['A',3]))
         sage: list(sorted(d.edges()))
         []
         sage: d.add_edge(2, 3)
         sage: list(sorted(d.edges()))
         [(2, 3, 1), (3, 2, 1)]
     """
     DiGraph.add_edge(self, i, j, label)
     if not self.has_edge(j, i):
         self.add_edge(j, i, 1)
Esempio n. 8
0
 def add_edge(self, i, j, label=1):
     """
     EXAMPLES::
     
         sage: from sage.combinat.root_system.dynkin_diagram import DynkinDiagram_class
         sage: d = DynkinDiagram_class(CartanType(['A',3]))
         sage: list(sorted(d.edges()))
         []
         sage: d.add_edge(2, 3)
         sage: list(sorted(d.edges()))
         [(2, 3, 1), (3, 2, 1)]
     """
     DiGraph.add_edge(self, i, j, label)
     if not self.has_edge(j,i):
         self.add_edge(j,i,1)
Esempio n. 9
0
        def cayley_graph_disabled(self, connecting_set=None):
            """

            AUTHORS:

            - Bobby Moretti (2007-08-10)

            - Robert Miller (2008-05-01): editing
            """
            if connecting_set is None:
                connecting_set = self.gens()
            else:
                try:
                    for g in connecting_set:
                        assert g in self
                except AssertionError:
                    raise RuntimeError(
                        "Each element of the connecting set must be in the group!"
                    )
                connecting_set = [self(g) for g in connecting_set]
            from sage.graphs.all import DiGraph
            arrows = {}
            for x in self:
                arrows[x] = {}
                for g in connecting_set:
                    xg = x * g  # cache the multiplication
                    if not xg == x:
                        arrows[x][xg] = g

            return DiGraph(arrows, implementation='networkx')
Esempio n. 10
0
 def digraph(self):
     """
     Returns a directed graph where the vertices are the individual
     species that make up this one.
     
     EXAMPLES::
     
         sage: X = species.SingletonSpecies()
         sage: B = species.CombinatorialSpecies()
         sage: B.define(X+B*B)
         sage: g = B.digraph(); g
         Multi-digraph on 4 vertices
     
     ::
     
         sage: g_c, labels = g.canonical_label(certify=True)
         sage: g.relabel()
         sage: g_r = g.canonical_label()
         sage: g_c == g_r
         True
         sage: list(sorted(labels.keys()))
         [Combinatorial species,
          Product of (Combinatorial species) and (Combinatorial species),
          Singleton species,
          Sum of (Singleton species) and (Product of (Combinatorial species) and (Combinatorial species))]
         sage: list(sorted(labels.values()))
         [0, 1, 2, 3]
     """
     from sage.graphs.all import DiGraph
     d = DiGraph(multiedges=True)
     self._add_to_digraph(d)
     return d
Esempio n. 11
0
 def __getitem__(self, i):
     r"""
     With a tuple (i,j) as argument, returns the scalar product
     `\langle
             \alpha^\vee_i, \alpha_j\rangle`.
     
     Otherwise, behaves as the usual DiGraph.__getitem__
     
     EXAMPLES: We use the `C_4` dynkin diagram as a cartan
     matrix::
     
         sage: g = DynkinDiagram(['C',4])
         sage: matrix([[g[i,j] for j in range(1,5)] for i in range(1,5)])
         [ 2 -1  0  0]
         [-1  2 -1  0]
         [ 0 -1  2 -2]
         [ 0  0 -1  2]
     
     The neighbors of a node can still be obtained in the usual way::
     
         sage: [g[i] for i in range(1,5)]
         [[2], [1, 3], [2, 4], [3]]
     """
     if not isinstance(i, tuple):
         return DiGraph.__getitem__(self, i)
     [i, j] = i
     if i == j:
         return 2
     elif self.has_edge(j, i):
         return -self.edge_label(j, i)
     else:
         return 0
Esempio n. 12
0
 def __getitem__(self, i):
     r"""
     With a tuple (i,j) as argument, returns the scalar product
     `\langle
             \alpha^\vee_i, \alpha_j\rangle`.
     
     Otherwise, behaves as the usual DiGraph.__getitem__
     
     EXAMPLES: We use the `C_4` dynkin diagram as a cartan
     matrix::
     
         sage: g = DynkinDiagram(['C',4])
         sage: matrix([[g[i,j] for j in range(1,5)] for i in range(1,5)])
         [ 2 -1  0  0]
         [-1  2 -1  0]
         [ 0 -1  2 -2]
         [ 0  0 -1  2]
     
     The neighbors of a node can still be obtained in the usual way::
     
         sage: [g[i] for i in range(1,5)]
         [[2], [1, 3], [2, 4], [3]]
     """
     if not isinstance(i, tuple):
         return DiGraph.__getitem__(self,i)
     [i,j] = i
     if i == j:
         return 2
     elif self.has_edge(j, i):
         return -self.edge_label(j, i)
     else:
         return 0
Esempio n. 13
0
        def digraph(self):
            """
            Returns the DiGraph associated to self.

            EXAMPLES::

                sage: C = Crystals().example(5)
                sage: C.digraph()
                Digraph on 6 vertices

            The edges of the crystal graph are by default colored using blue for edge 1, red for edge 2,
            and green for edge 3::

                sage: C = Crystals().example(3)
                sage: G = C.digraph()
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            One may also overwrite the colors::

                sage: C = Crystals().example(3)
                sage: G = C.digraph()
                sage: G.set_latex_options(color_by_label = {1:"red", 2:"purple", 3:"blue"})
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            Or one may add colors to yet unspecified edges::

                sage: C = Crystals().example(4)
                sage: G = C.digraph()
                sage: C.cartan_type()._index_set_coloring[4]="purple"
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            TODO: add more tests
            """
            from sage.graphs.all import DiGraph
            d = {}
            for x in self:
                d[x] = {}
                for i in self.index_set():
                    child = x.f(i)
                    if child is None:
                        continue
                    d[x][child]=i
            G = DiGraph(d)
            if have_dot2tex():
                G.set_latex_options(format="dot2tex", edge_labels = True, color_by_label = self.cartan_type()._index_set_coloring,
                                    edge_options = lambda (u,v,label): ({"backward":label ==0}))
            return G
Esempio n. 14
0
        def digraph(self):
            """
            Returns the DiGraph associated to self.

            EXAMPLES::

                sage: C = Crystals().example(5)
                sage: C.digraph()
                Digraph on 6 vertices

            The edges of the crystal graph are by default colored using blue for edge 1, red for edge 2,
            and green for edge 3::

                sage: C = Crystals().example(3)
                sage: G = C.digraph()
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            One may also overwrite the colors::

                sage: C = Crystals().example(3)
                sage: G = C.digraph()
                sage: G.set_latex_options(color_by_label = {1:"red", 2:"purple", 3:"blue"})
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            Or one may add colors to yet unspecified edges::

                sage: C = Crystals().example(4)
                sage: G = C.digraph()
                sage: C.cartan_type()._index_set_coloring[4]="purple"
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            TODO: add more tests
            """
            from sage.graphs.all import DiGraph
            d = {}
            for x in self:
                d[x] = {}
                for i in self.index_set():
                    child = x.f(i)
                    if child is None:
                        continue
                    d[x][child]=i
            G = DiGraph(d)
            if have_dot2tex():
                G.set_latex_options(format="dot2tex", edge_labels = True, color_by_label = self.cartan_type()._index_set_coloring,
                                    edge_options = lambda (u,v,label): ({"backward":label ==0}))
            return G
Esempio n. 15
0
    def __init__(self, t=None):
        """
        INPUT:

         - ``t`` - a Cartan type or None

        EXAMPLES::
        
            sage: d = DynkinDiagram(["A", 3])
            sage: d == loads(dumps(d))
            True

        Implementation note: if a Cartan type is given, then the nodes
        are initialized from the index set of this Cartan type.
        """
        DiGraph.__init__(self)
        self._cartan_type = t
        if t is not None:
            self.add_vertices(t.index_set())
Esempio n. 16
0
    def __init__(self, t = None):
        """
        INPUT:

         - ``t`` - a Cartan type or None

        EXAMPLES::
        
            sage: d = DynkinDiagram(["A", 3])
            sage: d == loads(dumps(d))
            True

        Implementation note: if a Cartan type is given, then the nodes
        are initialized from the index set of this Cartan type.
        """
        DiGraph.__init__(self)
        self._cartan_type = t
        if t is not None:
            self.add_vertices(t.index_set())
Esempio n. 17
0
def _dig6_to_digraph( dig6 ):
    """
    Returns the digraph obtained from the dig6 and edge data.

    INPUT:

    - ``dig6`` -- a pair ``(dig6, edges)`` where ``dig6`` is a string encoding a digraph and ``edges`` is a dict or tuple encoding edges

    EXAMPLES::

        sage: from sage.combinat.cluster_algebra_quiver.mutation_class import _digraph_to_dig6
        sage: from sage.combinat.cluster_algebra_quiver.mutation_class import _dig6_to_digraph
        sage: dg = ClusterQuiver(['A',4]).digraph()
        sage: data = _digraph_to_dig6(dg)
        sage: _dig6_to_digraph(data)
        Digraph on 4 vertices
        sage: _dig6_to_digraph(data).edges()
        [(0, 1, (1, -1)), (2, 1, (1, -1)), (2, 3, (1, -1))]
    """
    dig6, edges = dig6
    dg = DiGraph( dig6 )
    if not type(edges) == dict:
        edges = dict( edges )
    for edge in dg._backend.iterator_in_edges(dg,False):
        if edge in edges:
            dg.set_edge_label( edge[0],edge[1],edges[edge] )
        else:
            dg.set_edge_label( edge[0],edge[1], (1,-1) )
    return dg
Esempio n. 18
0
    def IntegerPartitions(n):
        """
        Returns the poset of integer partitions on the integer ``n``.

        A partition of a positive integer `n` is a non-increasing list
        of positive integers that sum to `n`. If `p` and `q` are
        integer partitions of `n`, then `p` covers `q` if and only
        if `q` is obtained from `p` by joining two parts of `p`
        (and sorting, if necessary).

        EXAMPLES::
        
            sage: P = Posets.IntegerPartitions(7); P
            Finite poset containing 15 elements
            sage: len(P.cover_relations())
            28
        """
        def lower_covers(partition):
            r"""
            Nested function for computing the lower covers
            of elements in the poset of integer partitions.
            """
            lc = []
            for i in range(0, len(partition) - 1):
                for j in range(i + 1, len(partition)):
                    new_partition = partition[:]
                    del new_partition[j]
                    del new_partition[i]
                    new_partition.append(partition[i] + partition[j])
                    new_partition.sort(reverse=True)
                    tup = tuple(new_partition)
                    if tup not in lc:
                        lc.append(tup)
            return lc

        from sage.combinat.partition import partitions_list
        H = DiGraph(
            dict([[tuple(p), lower_covers(p)] for p in partitions_list(n)]))
        return Poset(H.reverse())
Esempio n. 19
0
    def IntegerPartitions(n):
        """
        Returns the poset of integer partitions on the integer ``n``.

        A partition of a positive integer `n` is a non-increasing list
        of positive integers that sum to `n`. If `p` and `q` are
        integer partitions of `n`, then `p` covers `q` if and only
        if `q` is obtained from `p` by joining two parts of `p`
        (and sorting, if necessary).

        EXAMPLES::
        
            sage: P = Posets.IntegerPartitions(7); P
            Finite poset containing 15 elements
            sage: len(P.cover_relations())
            28
        """
        def lower_covers(partition):
            r"""
            Nested function for computing the lower covers
            of elements in the poset of integer partitions.
            """
            lc = []
            for i in range(0,len(partition)-1):
                for j in range(i+1,len(partition)):
                    new_partition = partition[:]
                    del new_partition[j]
                    del new_partition[i]
                    new_partition.append(partition[i]+partition[j])
                    new_partition.sort(reverse=True)
                    tup = tuple(new_partition)
                    if tup not in lc: 
                        lc.append(tup)
            return lc
        from sage.combinat.partition import partitions_list
        H = DiGraph(dict([[tuple(p),lower_covers(p)] for p in
            partitions_list(n)]))
        return Poset(H.reverse())
Esempio n. 20
0
    def _digraph(self):
        r"""
        Constructs the underlying digraph and stores the result as an
        attribute.

        EXAMPLES::
        
            sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
            sage: ops = [SwapIncreasingOperator(i) for i in range(2)]
            sage: Y = YangBaxterGraph(root=(1,2,3), operators=ops)
            sage: Y._digraph
            Digraph on 6 vertices
        """
        digraph = DiGraph()
        digraph.add_vertex(self._root)
        queue = [self._root]
        while queue:
            u = queue.pop()
            for (v, l) in self._succesors(u):
                if v not in digraph:
                    queue.append(v)
                digraph.add_edge(u, v, l)
        return digraph
Esempio n. 21
0
    def __init__(self):
        """
        EXAMPLES::

            sage: C = sage.categories.examples.crystals.NaiveCrystal()
            sage: C == Crystals().example(choice='naive')
            True
        """
        Parent.__init__(self, category = ClassicalCrystals())
        self.n = 2
        self._cartan_type = CartanType(['A',2])
        self.G = DiGraph(5)
        self.G.add_edges([ [0,1,1], [1,2,1], [2,3,1], [3,5,1],  [0,4,2], [4,5,2] ])
        self.module_generators = [ self(0) ]
Esempio n. 22
0
    def RestrictedIntegerPartitions(n):
        """
        Returns the poset of integer partitions on the integer `n`
        ordered by restricted refinement. That is, if `p` and `q`
        are integer partitions of `n`, then `p` covers `q` if and
        only if `q` is obtained from `p` by joining two distinct
        parts of `p` (and sorting, if necessary).

        EXAMPLES::
        
            sage: P = Posets.RestrictedIntegerPartitions(7); P
            Finite poset containing 15 elements
            sage: len(P.cover_relations())
            17
        """
        def lower_covers(partition):
            r"""
            Nested function for computing the lower covers of elements in the
            restricted poset of integer partitions.
            """
            lc = []
            for i in range(0,len(partition)-1):
                for j in range(i+1,len(partition)):
                    if partition[i] != partition[j]:
                        new_partition = partition[:]
                        del new_partition[j]
                        del new_partition[i]
                        new_partition.append(partition[i]+partition[j])
                        new_partition.sort(reverse=True)
                        tup = tuple(new_partition)
                        if tup not in lc: 
                            lc.append(tup)
            return lc
        from sage.combinat.partition import Partitions
        H = DiGraph(dict([[tuple(p),lower_covers(p)] for p in
            Partitions(n)]))
        return Poset(H.reverse())
Esempio n. 23
0
    def RestrictedIntegerPartitions(n):
        """
        Returns the poset of integer partitions on the integer `n`
        ordered by restricted refinement. That is, if `p` and `q`
        are integer partitions of `n`, then `p` covers `q` if and
        only if `q` is obtained from `p` by joining two distinct
        parts of `p` (and sorting, if necessary).

        EXAMPLES::
        
            sage: P = Posets.RestrictedIntegerPartitions(7); P
            Finite poset containing 15 elements
            sage: len(P.cover_relations())
            17
        """
        def lower_covers(partition):
            r"""
            Nested function for computing the lower covers of elements in the
            restricted poset of integer partitions.
            """
            lc = []
            for i in range(0, len(partition) - 1):
                for j in range(i + 1, len(partition)):
                    if partition[i] != partition[j]:
                        new_partition = partition[:]
                        del new_partition[j]
                        del new_partition[i]
                        new_partition.append(partition[i] + partition[j])
                        new_partition.sort(reverse=True)
                        tup = tuple(new_partition)
                        if tup not in lc:
                            lc.append(tup)
            return lc

        from sage.combinat.partition import Partitions
        H = DiGraph(dict([[tuple(p), lower_covers(p)] for p in Partitions(n)]))
        return Poset(H.reverse())
Esempio n. 24
0
    def to_dag(self):
        """
        Returns a directed acyclic graph corresponding to the skew
        partition.
        
        EXAMPLES::
        
            sage: dag = SkewPartition([[3, 2, 1], [1, 1]]).to_dag()
            sage: dag.edges()
            [('0,1', '0,2', None), ('0,1', '1,1', None)]
            sage: dag.vertices()
            ['0,1', '0,2', '1,1', '2,0']
        """
        i = 0

        #Make the skew tableau from the shape
        skew = [[1] * row_length for row_length in self.outer()]
        inner = self.inner()
        for i in range(len(inner)):
            for j in range(inner[i]):
                skew[i][j] = None

        G = DiGraph()
        for row in range(len(skew)):
            for column in range(len(skew[row])):
                if skew[row][column] is not None:
                    string = "%d,%d" % (row, column)
                    G.add_vertex(string)
                    #Check to see if there is a node to the right
                    if column != len(skew[row]) - 1:
                        newstring = "%d,%d" % (row, column + 1)
                        G.add_edge(string, newstring)

                    #Check to see if there is anything below
                    if row != len(skew) - 1:
                        if len(skew[row + 1]) > column:
                            if skew[row + 1][column] is not None:
                                newstring = "%d,%d" % (row + 1, column)
                                G.add_edge(string, newstring)
        return G
Esempio n. 25
0
    def to_dag(self):
        """
        Returns a directed acyclic graph corresponding to the skew
        partition.
        
        EXAMPLES::
        
            sage: dag = SkewPartition([[3, 2, 1], [1, 1]]).to_dag()
            sage: dag.edges()
            [('0,1', '0,2', None), ('0,1', '1,1', None)]
            sage: dag.vertices()
            ['0,1', '0,2', '1,1', '2,0']
        """
        i = 0

        #Make the skew tableau from the shape
        skew = [[1]*row_length for row_length in self.outer()]
        inner = self.inner()
        for i in range(len(inner)):
            for j in range(inner[i]):
                skew[i][j] = None

        G = DiGraph()
        for row in range(len(skew)):
            for column in range(len(skew[row])):
                if skew[row][column] is not None:
                    string = "%d,%d" % (row, column)
                    G.add_vertex(string)
                    #Check to see if there is a node to the right
                    if column != len(skew[row]) - 1:
                        newstring = "%d,%d" % (row, column+1)
                        G.add_edge(string, newstring)

                    #Check to see if there is anything below
                    if row != len(skew) - 1:
                        if len(skew[row+1]) > column:
                            if skew[row+1][column] is not None:
                                newstring = "%d,%d" % (row+1, column)
                                G.add_edge(string, newstring)
        return G
Esempio n. 26
0
    def to_digraph(self):
        r"""
        Returns a ``DiGraph`` object of the transition graph of the suffix 
        trie.

        EXAMPLES::

            sage: from sage.combinat.words.suffix_trees import SuffixTrie
            sage: w = Words("cao")("cac")
            sage: t = SuffixTrie(w)
            sage: d = t.to_digraph(); d
            Digraph on 6 vertices
            sage: d.adjacency_matrix()
            [0 1 0 1 0 0]
            [0 0 1 0 0 0]
            [0 0 0 0 1 0]
            [0 0 0 0 0 1]
            [0 0 0 0 0 0]
            [0 0 0 0 0 0]
        """
        dag = {}
        for ((u, letter), v) in self._transition_function.iteritems():
            dag.setdefault(u, {})[v] = letter
        return DiGraph(dag)
Esempio n. 27
0
    def _digraph(self):
        r"""
        Constructs the underlying digraph and stores the result as an
        attribute.

        EXAMPLES::
        
            sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
            sage: ops = [SwapIncreasingOperator(i) for i in range(2)]
            sage: Y = YangBaxterGraph(root=(1,2,3), operators=ops)
            sage: Y._digraph
            Digraph on 6 vertices
        """
        digraph = DiGraph()
        digraph.add_vertex(self._root)
        queue = [self._root]
        while queue:
            u = queue.pop()
            for (v, l) in self._succesors(u):
                if v not in digraph:
                    queue.append(v)
                digraph.add_edge(u, v, l)
        return digraph
Esempio n. 28
0
    def RandomPoset(n, p):
        r"""
        Generate a random poset on ``n`` vertices according to a
        probability ``p``.

        INPUT:

        - ``n`` - number of vertices, a non-negative integer

        - ``p`` - a probability, a real number between 0 and 1 (inclusive)

        OUTPUT:

        A poset on ``n`` vertices.  The construction decides to make an
        ordered pair of vertices comparable in the poset with probability
        ``p``, however a pair is not made comparable if it would violate
        the defining properties of a poset, such as transitivity.

        So in practice, once the probability exceeds a small number the
        generated posets may be very similar to a chain.  So to create
        interesting examples, keep the probability small, perhaps on the
        order of `1/n`.

        EXAMPLES::

            sage: Posets.RandomPoset(17,.15)
            Finite poset containing 17 elements

        TESTS::

            sage: Posets.RandomPoset('junk', 0.5)
            Traceback (most recent call last):
            ...
            TypeError: number of elements must be an integer, not junk

            sage: Posets.RandomPoset(-6, 0.5)
            Traceback (most recent call last):
            ...
            ValueError: number of elements must be non-negative, not -6

            sage: Posets.RandomPoset(6, 'garbage')
            Traceback (most recent call last):
            ...
            TypeError: probability must be a real number, not garbage

            sage: Posets.RandomPoset(6, -0.5)
            Traceback (most recent call last):
            ...
            ValueError: probability must be between 0 and 1, not -0.5
        """
        try:
            n = Integer(n)
        except:
            raise TypeError(
                "number of elements must be an integer, not {0}".format(n))
        if n < 0:
            raise ValueError(
                "number of elements must be non-negative, not {0}".format(n))
        try:
            p = float(p)
        except:
            raise TypeError(
                "probability must be a real number, not {0}".format(p))
        if p < 0 or p > 1:
            raise ValueError(
                "probability must be between 0 and 1, not {0}".format(p))

        D = DiGraph(loops=False, multiedges=False)
        D.add_vertices(range(n))
        for i in range(n):
            for j in range(n):
                if random.random() < p:
                    D.add_edge(i, j)
                    if not D.is_directed_acyclic():
                        D.delete_edge(i, j)
        return Poset(D, cover_relations=False)
Esempio n. 29
0
def _digraph_mutate(dg, k, frozen=None):
    """
    Return a digraph obtained from ``dg`` by mutating at vertex ``k``.

    Vertices can be labelled by anything, and frozen vertices must
    be explicitly given.

    INPUT:

    - ``dg`` -- a digraph with integral edge labels with ``n+m`` vertices
    - ``k`` -- the vertex at which ``dg`` is mutated
    - ``frozen`` -- the list of frozen vertices (default is the empty list)

    EXAMPLES::

        sage: from sage.combinat.cluster_algebra_quiver.mutation_class import _digraph_mutate
        sage: from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver
        sage: dg = ClusterQuiver(['A',4]).digraph()
        sage: dg.edges()
        [(0, 1, (1, -1)), (2, 1, (1, -1)), (2, 3, (1, -1))]
        sage: _digraph_mutate(dg,2).edges()
        [(0, 1, (1, -1)), (1, 2, (1, -1)), (3, 2, (1, -1))]

    TESTS::

       sage: dg = DiGraph([('a','b',(1,-1)),('c','a',(1,-1))])
       sage: _digraph_mutate(dg,'a').edges()
       [('a', 'c', (1, -1)), ('b', 'a', (1, -1)), ('c', 'b', (1, -1))]
       sage: _digraph_mutate(dg,'a',frozen=['b','c']).edges()
       [('a', 'c', (1, -1)), ('b', 'a', (1, -1))]

       sage: dg = DiGraph([('a','b',(2,-2)),('c','a',(2,-2)),('b','c',(2,-2))])
       sage: _digraph_mutate(dg,'a').edges()
       [('a', 'c', (2, -2)), ('b', 'a', (2, -2)), ('c', 'b', (2, -2))]
    """
    # assert sorted(list(dg)) == list(range(n + m))
    # this is not assumed anymore
    if frozen is None:
        frozen = []

    edge_it = dg.incoming_edge_iterator(dg, True)
    edges = {(v1, v2): label for v1, v2, label in edge_it}
    edge_it = dg.incoming_edge_iterator([k], True)
    in_edges = [(v1, v2, label) for v1, v2, label in edge_it]
    edge_it = dg.outgoing_edge_iterator([k], True)
    out_edges = [(v1, v2, label) for v1, v2, label in edge_it]

    in_edges_new = [(v2, v1, (-label[1], -label[0]))
                    for (v1, v2, label) in in_edges]
    out_edges_new = [(v2, v1, (-label[1], -label[0]))
                     for (v1, v2, label) in out_edges]
    diag_edges_new = []
    diag_edges_del = []

    for (v1, v2, label1) in in_edges:
        l11, l12 = label1
        for (w1, w2, label2) in out_edges:
            if v1 in frozen and w2 in frozen:
                continue
            l21, l22 = label2
            if (v1, w2) in edges:
                diag_edges_del.append((v1, w2))
                a, b = edges[(v1, w2)]
                a, b = a + l11 * l21, b - l12 * l22
                diag_edges_new.append((v1, w2, (a, b)))
            elif (w2, v1) in edges:
                diag_edges_del.append((w2, v1))
                a, b = edges[(w2, v1)]
                a, b = b + l11 * l21, a - l12 * l22
                if a < 0:
                    diag_edges_new.append((w2, v1, (b, a)))
                elif a > 0:
                    diag_edges_new.append((v1, w2, (a, b)))
            else:
                a, b = l11 * l21, -l12 * l22
                diag_edges_new.append((v1, w2, (a, b)))

    del_edges = [tuple(ed[:2]) for ed in in_edges + out_edges]
    del_edges += diag_edges_del
    new_edges = in_edges_new + out_edges_new
    new_edges += diag_edges_new
    new_edges += [(v1, v2, edges[(v1, v2)]) for (v1, v2) in edges
                  if (v1, v2) not in del_edges]

    dg_new = DiGraph()
    dg_new.add_vertices(list(dg))
    for v1, v2, label in new_edges:
        dg_new.add_edge(v1, v2, label)

    return dg_new
Esempio n. 30
0
def _is_valid_digraph_edge_set( edges, frozen=0 ):
    """
    Returns True if the input data is the edge set of a digraph for a quiver (no loops, no 2-cycles, edge-labels of the specified format), and returns False otherwise.

    INPUT:

    - ``frozen`` -- (integer; default:0) The number of frozen vertices.

    EXAMPLES::

        sage: from sage.combinat.cluster_algebra_quiver.mutation_class import _is_valid_digraph_edge_set
        sage: _is_valid_digraph_edge_set( [[0,1,'a'],[2,3,(1,-1)]] )
        The given digraph has edge labels which are not integral or integral 2-tuples.
        False
        sage: _is_valid_digraph_edge_set( [[0,1],[2,3,(1,-1)]] )
        True
        sage: _is_valid_digraph_edge_set( [[0,1,'a'],[2,3,(1,-1)],[3,2,(1,-1)]] )
        The given digraph or edge list contains oriented 2-cycles.
        False
    """
    try:
        dg = DiGraph()
        dg.allow_multiple_edges(True)
        dg.add_edges( edges )

        # checks if the digraph contains loops
        if dg.has_loops():
            print "The given digraph or edge list contains loops."
            return False

        # checks if the digraph contains oriented 2-cycles
        if _has_two_cycles( dg ):
            print "The given digraph or edge list contains oriented 2-cycles."
            return False

        # checks if all edge labels are 'None', positive integers or tuples of positive integers
        if not all( i == None or ( i in ZZ and i > 0 ) or ( type(i) == tuple and len(i) == 2 and i[0] in ZZ and i[1] in ZZ ) for i in dg.edge_labels() ):
            print "The given digraph has edge labels which are not integral or integral 2-tuples."
            return False

        # checks if all edge labels for multiple edges are 'None' or positive integers
        if dg.has_multiple_edges():
            for e in set( dg.multiple_edges(labels=False) ):
                if not all( i == None or ( i in ZZ and i > 0 ) for i in dg.edge_label( e[0], e[1] ) ):
                    print "The given digraph or edge list contains multiple edges with non-integral labels."
                    return False

        n = dg.order() - frozen
        if n < 0:
            print "The number of frozen variables is larger than the number of vertices."
            return False

        if [ e for e in dg.edges(labels=False) if e[0] >= n] <> []:
            print "The given digraph or edge list contains edges within the frozen vertices."
            return False

        return True
    except StandardError:
        print "Could not even build a digraph from the input data."
        return False
Esempio n. 31
0
    def uncompactify(self):
        r"""
        Returns the tree obtained from self by splitting edges so that they
        are labelled by exactly one letter. The resulting tree is
        isomorphic to the suffix trie.

        EXAMPLES::

            sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree, SuffixTrie
            sage: abbab = Words("ab")("abbab")
            sage: s = SuffixTrie(abbab)
            sage: t = ImplicitSuffixTree(abbab)
            sage: t.uncompactify().is_isomorphic(s.to_digraph())
            True
        """
        tree = self.to_digraph(word_labels=True)
        newtree = DiGraph()
        newtree.add_vertices(range(tree.order()))
        new_node = tree.order() + 1
        for (u, v, label) in tree.edge_iterator():
            if len(label) == 1:
                newtree.add_edge(u, v)
            else:
                newtree.add_edge(u, new_node, label[0])
                for w in label[1:-1]:
                    newtree.add_edge(new_node, new_node + 1, w)
                    new_node += 1
                newtree.add_edge(new_node, v, label[-1])
                new_node += 1
        return newtree
Esempio n. 32
0
def Hasse_diagram_from_incidences(atom_to_coatoms, coatom_to_atoms,
                                  face_constructor=None,
                                  required_atoms=None,
                                  key = None,
                                  **kwds):
    r"""
    Compute the Hasse diagram of an atomic and coatomic lattice.

    INPUT:

    - ``atom_to_coatoms`` -- list, ``atom_to_coatom[i]`` should list all
      coatoms over the ``i``-th atom;

    - ``coatom_to_atoms`` -- list, ``coatom_to_atom[i]`` should list all
      atoms under the ``i``-th coatom;

    - ``face_constructor`` -- function or class taking as the first two
      arguments sorted :class:`tuple` of integers and any keyword arguments.
      It will be called to construct a face over atoms passed as the first
      argument and under coatoms passed as the second argument. Default
      implementation will just return these two tuples as a tuple;

    - ``required_atoms`` -- list of atoms (default:None). Each
      non-empty "face" requires at least on of the specified atoms
      present. Used to ensure that each face has a vertex.

    - ``key`` -- any hashable value (default: None). It is passed down
      to :class:`~sage.combinat.posets.posets.FinitePoset`.

    - all other keyword arguments will be passed to ``face_constructor`` on
      each call.

    OUTPUT:

    - :class:`finite poset <sage.combinat.posets.posets.FinitePoset>` with
      elements constructed by ``face_constructor``.

    .. NOTE::

        In addition to the specified partial order, finite posets in Sage have
        internal total linear order of elements which extends the partial one.
        This function will try to make this internal order to start with the
        bottom and atoms in the order corresponding to ``atom_to_coatoms`` and
        to finish with coatoms in the order corresponding to
        ``coatom_to_atoms`` and the top. This may not be possible if atoms and
        coatoms are the same, in which case the preference is given to the
        first list.

    ALGORITHM:

    The detailed description of the used algorithm is given in [KP2002]_.

    The code of this function follows the pseudo-code description in the
    section 2.5 of the paper, although it is mostly based on frozen sets
    instead of sorted lists - this makes the implementation easier and should
    not cost a big performance penalty. (If one wants to make this function
    faster, it should be probably written in Cython.)

    While the title of the paper mentions only polytopes, the algorithm (and
    the implementation provided here) is applicable to any atomic and coatomic
    lattice if both incidences are given, see Section 3.4.

    In particular, this function can be used for strictly convex cones and
    complete fans.

    REFERENCES:

    ..  [KP2002]
        Volker Kaibel and Marc E. Pfetsch,
        "Computing the Face Lattice of a Polytope from its Vertex-Facet
        Incidences", Computational Geometry: Theory and Applications,
        Volume 23, Issue 3 (November 2002), 281-290.
        Available at http://portal.acm.org/citation.cfm?id=763203
        and free of charge at http://arxiv.org/abs/math/0106043

    AUTHORS:

    - Andrey Novoseltsev (2010-05-13) with thanks to Marshall Hampton for the
      reference.

    EXAMPLES:

    Let's construct the Hasse diagram of a lattice of subsets of {0, 1, 2}.
    Our atoms are {0}, {1}, and {2}, while our coatoms are {0,1}, {0,2}, and
    {1,2}. Then incidences are ::

        sage: atom_to_coatoms = [(0,1), (0,2), (1,2)]
        sage: coatom_to_atoms = [(0,1), (0,2), (1,2)]

    and we can compute the Hasse diagram as ::

        sage: L = sage.geometry.cone.Hasse_diagram_from_incidences(
        ...                       atom_to_coatoms, coatom_to_atoms)
        sage: L
        Finite poset containing 8 elements
        sage: for level in L.level_sets(): print level
        [((), (0, 1, 2))]
        [((0,), (0, 1)), ((1,), (0, 2)), ((2,), (1, 2))]
        [((0, 1), (0,)), ((0, 2), (1,)), ((1, 2), (2,))]
        [((0, 1, 2), ())]

    For more involved examples see the *source code* of
    :meth:`sage.geometry.cone.ConvexRationalPolyhedralCone.face_lattice` and
    :meth:`sage.geometry.fan.RationalPolyhedralFan._compute_cone_lattice`.
    """
    from sage.graphs.all import DiGraph
    from sage.combinat.posets.posets import FinitePoset
    def default_face_constructor(atoms, coatoms, **kwds):
        return (atoms, coatoms)
    if face_constructor is None:
        face_constructor = default_face_constructor
    atom_to_coatoms = [frozenset(atc) for atc in atom_to_coatoms]
    A = frozenset(range(len(atom_to_coatoms)))  # All atoms
    coatom_to_atoms = [frozenset(cta) for cta in coatom_to_atoms]
    C = frozenset(range(len(coatom_to_atoms)))  # All coatoms
    # Comments with numbers correspond to steps in Section 2.5 of the article
    L = DiGraph(1)       # 3: initialize L
    faces = dict()
    atoms = frozenset()
    coatoms = C
    faces[atoms, coatoms] = 0
    next_index = 1
    Q = [(atoms, coatoms)]              # 4: initialize Q with the empty face
    while Q:                            # 5
        q_atoms, q_coatoms = Q.pop()    # 6: remove some q from Q
        q = faces[q_atoms, q_coatoms]
        # 7: compute H = {closure(q+atom) : atom not in atoms of q}
        H = dict()
        candidates = set(A.difference(q_atoms))
        for atom in candidates:
            coatoms = q_coatoms.intersection(atom_to_coatoms[atom])
            atoms = A
            for coatom in coatoms:
                atoms = atoms.intersection(coatom_to_atoms[coatom])
            H[atom] = (atoms, coatoms)
        # 8: compute the set G of minimal sets in H
        minimals = set([])
        while candidates:
            candidate = candidates.pop()
            atoms = H[candidate][0]
            if atoms.isdisjoint(candidates) and atoms.isdisjoint(minimals):
                minimals.add(candidate)
        # Now G == {H[atom] : atom in minimals}
        for atom in minimals:   # 9: for g in G:
            g_atoms, g_coatoms = H[atom]
            if not required_atoms is None:
                if g_atoms.isdisjoint(required_atoms):
                    continue
            if (g_atoms, g_coatoms) in faces:
                g = faces[g_atoms, g_coatoms]
            else:               # 11: if g was newly created
                g = next_index
                faces[g_atoms, g_coatoms] = g
                next_index += 1
                Q.append((g_atoms, g_coatoms))  # 12
            L.add_edge(q, g)                    # 14
    # End of algorithm, now construct a FinitePoset.
    # In principle, it is recommended to use Poset or in this case perhaps
    # even LatticePoset, but it seems to take several times more time
    # than the above computation, makes unnecessary copies, and crashes.
    # So for now we will mimic the relevant code from Poset.

    # Enumeration of graph vertices must be a linear extension of the poset
    new_order = L.topological_sort()
    # Make sure that coatoms are in the end in proper order
    tail = [faces[atoms, frozenset([coatom])]
            for coatom, atoms in enumerate(coatom_to_atoms)]
    tail.append(faces[A, frozenset()])
    new_order = [n for n in new_order if n not in tail] + tail
    # Make sure that atoms are in the beginning in proper order
    head = [0] # We know that the empty face has index 0
    head.extend(faces[frozenset([atom]), coatoms]
                for atom, coatoms in enumerate(atom_to_coatoms)
                if required_atoms is None or atom in required_atoms)
    new_order = head + [n for n in new_order if n not in head]
    # "Invert" this list to a dictionary
    labels = dict()
    for new, old in enumerate(new_order):
        labels[old] = new
    L.relabel(labels)
    # Construct the actual poset elements
    elements = [None] * next_index
    for face, index in faces.items():
        atoms, coatoms = face
        elements[labels[index]] = face_constructor(
                        tuple(sorted(atoms)), tuple(sorted(coatoms)), **kwds)
    return FinitePoset(L, elements, key = key)
Esempio n. 33
0
def _digraph_mutate(dg, k, frozen=None):
    """
    Return a digraph obtained from ``dg`` by mutating at vertex ``k``.

    Vertices can be labelled by anything, and frozen vertices must
    be explicitly given.

    INPUT:

    - ``dg`` -- a digraph with integral edge labels with ``n+m`` vertices
    - ``k`` -- the vertex at which ``dg`` is mutated
    - ``frozen`` -- the list of frozen vertices (default is the empty list)

    EXAMPLES::

        sage: from sage.combinat.cluster_algebra_quiver.mutation_class import _digraph_mutate
        sage: from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver
        sage: dg = ClusterQuiver(['A',4]).digraph()
        sage: dg.edges()
        [(0, 1, (1, -1)), (2, 1, (1, -1)), (2, 3, (1, -1))]
        sage: _digraph_mutate(dg,2).edges()
        [(0, 1, (1, -1)), (1, 2, (1, -1)), (3, 2, (1, -1))]

    TESTS::

       sage: dg = DiGraph([('a','b',(1,-1)),('c','a',(1,-1))])
       sage: _digraph_mutate(dg,'a').edges()
       [('a', 'c', (1, -1)), ('b', 'a', (1, -1)), ('c', 'b', (1, -1))]
       sage: _digraph_mutate(dg,'a',frozen=['b','c']).edges()
       [('a', 'c', (1, -1)), ('b', 'a', (1, -1))]

       sage: dg = DiGraph([('a','b',(2,-2)),('c','a',(2,-2)),('b','c',(2,-2))])
       sage: _digraph_mutate(dg,'a').edges()
       [('a', 'c', (2, -2)), ('b', 'a', (2, -2)), ('c', 'b', (2, -2))]
    """
    # assert sorted(list(dg)) == list(range(n + m))
    # this is not assumed anymore
    if frozen is None:
        frozen = []

    edge_it = dg.incoming_edge_iterator(dg, True)
    edges = {(v1, v2): label for v1, v2, label in edge_it}
    edge_it = dg.incoming_edge_iterator([k], True)
    in_edges = [(v1, v2, label) for v1, v2, label in edge_it]
    edge_it = dg.outgoing_edge_iterator([k], True)
    out_edges = [(v1, v2, label) for v1, v2, label in edge_it]

    in_edges_new = [(v2, v1, (-label[1], -label[0]))
                    for (v1, v2, label) in in_edges]
    out_edges_new = [(v2, v1, (-label[1], -label[0]))
                     for (v1, v2, label) in out_edges]
    diag_edges_new = []
    diag_edges_del = []

    for (v1, v2, label1) in in_edges:
        l11, l12 = label1
        for (w1, w2, label2) in out_edges:
            if v1 in frozen and w2 in frozen:
                continue
            l21, l22 = label2
            if (v1, w2) in edges:
                diag_edges_del.append((v1, w2))
                a, b = edges[(v1, w2)]
                a, b = a + l11 * l21, b - l12 * l22
                diag_edges_new.append((v1, w2, (a, b)))
            elif (w2, v1) in edges:
                diag_edges_del.append((w2, v1))
                a, b = edges[(w2, v1)]
                a, b = b + l11 * l21, a - l12 * l22
                if a < 0:
                    diag_edges_new.append((w2, v1, (b, a)))
                elif a > 0:
                    diag_edges_new.append((v1, w2, (a, b)))
            else:
                a, b = l11 * l21, -l12 * l22
                diag_edges_new.append((v1, w2, (a, b)))

    del_edges = [tuple(ed[:2]) for ed in in_edges + out_edges]
    del_edges += diag_edges_del
    new_edges = in_edges_new + out_edges_new
    new_edges += diag_edges_new
    new_edges += [(v1, v2, edges[(v1, v2)]) for (v1, v2) in edges
                  if (v1, v2) not in del_edges]

    dg_new = DiGraph()
    dg_new.add_vertices(list(dg))
    for v1, v2, label in new_edges:
        dg_new.add_edge(v1, v2, label)

    return dg_new
Esempio n. 34
0
class NaiveCrystal(UniqueRepresentation, Parent):
    r"""
    This is an example of a "crystal" which does not come from any kind of
    representation, designed primarily to test the Stembridge local rules with.
    The crystal has vertices labeled 0 through 5, with 0 the highest weight.
    
    The code here could also possibly be generalized to create a class that
    automatically builds a crystal from an edge-colored digraph, if someone
    feels adventurous.

    Currently, only the methods :meth:`highest_weight_vector`, :meth:`e`, and :meth:`f` are
    guaranteed to work.

    EXAMPLES::

        sage: C = Crystals().example(choice='naive')
        sage: C.highest_weight_vector()
        0
    """
    def __init__(self):
        """
        EXAMPLES::

            sage: C = sage.categories.examples.crystals.NaiveCrystal()
            sage: C == Crystals().example(choice='naive')
            True
        """
        Parent.__init__(self, category=ClassicalCrystals())
        self.n = 2
        self._cartan_type = CartanType(['A', 2])
        self.G = DiGraph(5)
        self.G.add_edges([[0, 1, 1], [1, 2, 1], [2, 3, 1], [3, 5, 1],
                          [0, 4, 2], [4, 5, 2]])
        self.module_generators = [self(0)]

    def __repr__(self):
        """
        EXAMPLES::

            sage: Crystals().example(choice='naive')
            A broken crystal, defined by digraph, of dimension five.
        """
        return "A broken crystal, defined by digraph, of dimension five."

    class Element(ElementWrapper):
        def e(self, i):
            r"""
            Returns the action of `e_i` on ``self``.

            EXAMPLES::

                sage: C = Crystals().example(choice='naive')
                sage: [[c,i,c.e(i)] for i in C.index_set() for c in [C(j) for j in [0..5]] if c.e(i) is not None]
                [[1, 1, 0], [2, 1, 1], [3, 1, 2], [5, 1, 3], [4, 2, 0], [5, 2, 4]]
            """
            assert i in self.index_set()
            for edge in self.parent().G.edges():
                if edge[1] == int(str(self)) and edge[2] == i:
                    return self.parent()(edge[0])
            return None

        def f(self, i):
            r"""
            Returns the action of `f_i` on ``self``.

            EXAMPLES::

                sage: C = Crystals().example(choice='naive')
                sage: [[c,i,c.f(i)] for i in C.index_set() for c in [C(j) for j in [0..5]] if c.f(i) is not None]
                [[0, 1, 1], [1, 1, 2], [2, 1, 3], [3, 1, 5], [0, 2, 4], [4, 2, 5]]
            """
            assert i in self.index_set()
            for edge in self.parent().G.edges_incident(int(str(self))):
                if edge[2] == i:
                    return self.parent()(edge[1])
            return None
Esempio n. 35
0
        def digraph(self, subset=None, index_set=None, depth=None):
            """
            Return the DiGraph associated to ``self``.

            INPUT:

            - ``subset`` -- (optional) a subset of vertices for
              which the digraph should be constructed

            - ``index_set`` -- (optional) the index set to draw arrows

            - ``depth`` -- the depth to draw; optional only for finite crystals

            EXAMPLES::

                sage: T = crystals.Tableaux(['A',2], shape=[2,1])
                sage: T.digraph()
                Digraph on 8 vertices
                sage: S = T.subcrystal(max_depth=2)
                sage: len(S)
                5
                sage: G = T.digraph(subset=list(S))
                sage: G.is_isomorphic(T.digraph(depth=2), edge_labels=True)
                True

            TESTS:

            The following example demonstrates the speed improvement.
            The speedup in non-affine types is small however::

                sage: depth = 5
                sage: C = crystals.AlcovePaths(['A',2,1], [1,1,0])
                sage: general_digraph = Crystals().parent_class.digraph
                sage: S = C.subcrystal(max_depth=depth, direction='lower')
                sage: %timeit C.digraph(depth=depth) # not tested
                10 loops, best of 3: 48.9 ms per loop
                sage: %timeit general_digraph(C, subset=S) # not tested
                10 loops, best of 3: 96.5 ms per loop
                sage: G1 = C.digraph(depth=depth)
                sage: G2 = general_digraph(C, subset=S)
                sage: G1.is_isomorphic(G2, edge_labels=True)
                True
            """
            if subset is not None:
                return Crystals().parent_class.digraph(self, subset, index_set)

            if self not in Crystals().Finite() and depth is None:
                raise NotImplementedError(
                    "crystals not known to be finite must"
                    " specify either the subset or depth")

            from sage.graphs.all import DiGraph
            if index_set is None:
                index_set = self.index_set()

            rank = 0
            d = {g: {} for g in self.module_generators}
            visited = set(d.keys())

            while depth is None or rank < depth:
                recently_visited = set()
                for x in visited:
                    d.setdefault(x, {})  # does nothing if there's a default
                    for i in index_set:
                        xfi = x.f(i)
                        if xfi is not None:
                            d[x][xfi] = i
                            recently_visited.add(xfi)
                if not recently_visited:  # No new nodes, nothing more to do
                    break
                rank += 1
                visited = recently_visited

            G = DiGraph(d)
            if have_dot2tex():
                G.set_latex_options(
                    format="dot2tex",
                    edge_labels=True,
                    color_by_label=self.cartan_type()._index_set_coloring)
            return G
Esempio n. 36
0
        def digraph(self, subset=None, index_set=None, depth=None):
            """
            Return the DiGraph associated to ``self``.

            INPUT:

            - ``subset`` -- (optional) a subset of vertices for
              which the digraph should be constructed

            - ``index_set`` -- (optional) the index set to draw arrows

            - ``depth`` -- the depth to draw; optional only for finite crystals

            EXAMPLES::

                sage: T = crystals.Tableaux(['A',2], shape=[2,1])
                sage: T.digraph()
                Digraph on 8 vertices
                sage: S = T.subcrystal(max_depth=2)
                sage: len(S)
                5
                sage: G = T.digraph(subset=list(S))
                sage: G.is_isomorphic(T.digraph(depth=2), edge_labels=True)
                True

            TESTS:

            The following example demonstrates the speed improvement.
            The speedup in non-affine types is small however::

                sage: depth = 5
                sage: C = crystals.AlcovePaths(['A',2,1], [1,1,0])
                sage: general_digraph = Crystals().parent_class.digraph
                sage: S = C.subcrystal(max_depth=depth, direction='lower')
                sage: %timeit C.digraph(depth=depth) # not tested
                10 loops, best of 3: 48.9 ms per loop
                sage: %timeit general_digraph(C, subset=S) # not tested
                10 loops, best of 3: 96.5 ms per loop
                sage: G1 = C.digraph(depth=depth)
                sage: G2 = general_digraph(C, subset=S)
                sage: G1.is_isomorphic(G2, edge_labels=True)
                True
            """
            if subset is not None:
                return Crystals().parent_class.digraph(self, subset, index_set)

            if self not in Crystals().Finite() and depth is None:
                raise NotImplementedError("crystals not known to be finite must"
                                          " specify either the subset or depth")

            from sage.graphs.all import DiGraph
            if index_set is None:
                index_set = self.index_set()

            rank = 0
            d = {g: {} for g in self.module_generators}
            visited = set(d.keys())

            while depth is None or rank < depth:
                recently_visited = set()
                for x in visited:
                    d.setdefault(x, {}) # does nothing if there's a default
                    for i in index_set:
                        xfi = x.f(i)
                        if xfi is not None:
                            d[x][xfi] = i
                            recently_visited.add(xfi)
                if not recently_visited: # No new nodes, nothing more to do
                    break
                rank += 1
                visited = recently_visited

            G = DiGraph(d)
            if have_dot2tex():
                G.set_latex_options(format="dot2tex",
                                    edge_labels=True,
                                    color_by_label=self.cartan_type()._index_set_coloring)
            return G
Esempio n. 37
0
    def RandomPoset(n,p):
        r"""
        Generate a random poset on ``n`` vertices according to a
        probability ``p``.

        INPUT:

        - ``n`` - number of vertices, a non-negative integer

        - ``p`` - a probability, a real number between 0 and 1 (inclusive)

        OUTPUT:

        A poset on ``n`` vertices.  The construction decides to make an
        ordered pair of vertices comparable in the poset with probability
        ``p``, however a pair is not made comparable if it would violate
        the defining properties of a poset, such as transitivity.

        So in practice, once the probability exceeds a small number the
        generated posets may be very similar to a chain.  So to create
        interesting examples, keep the probability small, perhaps on the
        order of `1/n`.

        EXAMPLES::

            sage: Posets.RandomPoset(17,.15)
            Finite poset containing 17 elements

        TESTS::

            sage: Posets.RandomPoset('junk', 0.5)
            Traceback (most recent call last):
            ...
            TypeError: number of elements must be an integer, not junk

            sage: Posets.RandomPoset(-6, 0.5)
            Traceback (most recent call last):
            ...
            ValueError: number of elements must be non-negative, not -6

            sage: Posets.RandomPoset(6, 'garbage')
            Traceback (most recent call last):
            ...
            TypeError: probability must be a real number, not garbage

            sage: Posets.RandomPoset(6, -0.5)
            Traceback (most recent call last):
            ...
            ValueError: probability must be between 0 and 1, not -0.5
        """
        try:
            n = Integer(n)
        except:
            raise TypeError("number of elements must be an integer, not {0}".format(n))
        if n < 0:
            raise ValueError("number of elements must be non-negative, not {0}".format(n))
        try:
            p = float(p)
        except:
            raise TypeError("probability must be a real number, not {0}".format(p))
        if p < 0 or p> 1:
            raise ValueError("probability must be between 0 and 1, not {0}".format(p))
        
        D = DiGraph(loops=False,multiedges=False)
        D.add_vertices(range(n))
        for i in range(n):
            for j in range(n):
                if random.random() < p:
                    D.add_edge(i,j)
                    if not D.is_directed_acyclic():
                        D.delete_edge(i,j)
        return Poset(D,cover_relations=False)
Esempio n. 38
0
class NaiveCrystal(UniqueRepresentation, Parent):
    r"""
    This is an example of a "crystal" which does not come from any kind of
    representation, designed primarily to test the Stembridge local rules with.
    The crystal has vertices labeled 0 through 5, with 0 the highest weight.

    The code here could also possibly be generalized to create a class that
    automatically builds a crystal from an edge-colored digraph, if someone
    feels adventurous.

    Currently, only the methods :meth:`highest_weight_vector`, :meth:`e`, and :meth:`f` are
    guaranteed to work.

    EXAMPLES::

        sage: C = Crystals().example(choice='naive')
        sage: C.highest_weight_vector()
        0
    """
    def __init__(self):
        """
        EXAMPLES::

            sage: C = sage.categories.examples.crystals.NaiveCrystal()
            sage: C == Crystals().example(choice='naive')
            True
        """
        Parent.__init__(self, category = ClassicalCrystals())
        self.n = 2
        self._cartan_type = CartanType(['A',2])
        self.G = DiGraph(5)
        self.G.add_edges([ [0,1,1], [1,2,1], [2,3,1], [3,5,1],  [0,4,2], [4,5,2] ])
        self.module_generators = [ self(0) ]

    def __repr__(self):
        """
        EXAMPLES::

            sage: Crystals().example(choice='naive')
            A broken crystal, defined by digraph, of dimension five.
        """
        return "A broken crystal, defined by digraph, of dimension five."

    class Element(ElementWrapper):
        def e(self, i):
            r"""
            Returns the action of `e_i` on ``self``.

            EXAMPLES::

                sage: C = Crystals().example(choice='naive')
                sage: [[c,i,c.e(i)] for i in C.index_set() for c in [C(j) for j in [0..5]] if c.e(i) is not None]
                [[1, 1, 0], [2, 1, 1], [3, 1, 2], [5, 1, 3], [4, 2, 0], [5, 2, 4]]
            """
            assert i in self.index_set()
            for edge in self.parent().G.edges():
               if edge[1]==int(str(self)) and edge[2]==i:
                   return self.parent()(edge[0])
            return None

        def f(self, i):
            r"""
            Returns the action of `f_i` on ``self``.

            EXAMPLES::

                sage: C = Crystals().example(choice='naive')
                sage: [[c,i,c.f(i)] for i in C.index_set() for c in [C(j) for j in [0..5]] if c.f(i) is not None]
                [[0, 1, 1], [1, 1, 2], [2, 1, 3], [3, 1, 5], [0, 2, 4], [4, 2, 5]]
            """
            assert i in self.index_set()
            for edge in self.parent().G.edges_incident(int(str(self))):
                if edge[2] == i:
                    return self.parent()(edge[1])
            return None
Esempio n. 39
0
        def dual_equivalence_graph(self,
                                   X=None,
                                   index_set=None,
                                   directed=True):
            r"""
            Return the dual equivalence graph indexed by ``index_set``
            on the subset ``X`` of ``self``.

            Let `b \in B` be an element of weight `0`, so `\varepsilon_j(b)
            = \varphi_j(b)` for all `j \in I`, where `I` is the indexing
            set. We say `b'` is an `i`-elementary dual equivalence
            transformation of `b` (where `i \in I`) if

            * `\varepsilon_i(b) = 1` and `\varepsilon_{i-1}(b) = 0`, and
            * `b' = f_{i-1} f_i e_{i-1} e_i b`.

            We can do the inverse procedure by interchanging `i` and `i-1`
            above.

            .. NOTE::

                If the index set is not an ordered interval, we let
                `i - 1` mean the index appearing before `i` in `I`.

            This definition comes from [As2008]_ Section 4 (where our
            `\varphi_j(b)` and `\varepsilon_j(b)` are denoted by
            `\epsilon(b, j)` and `-\delta(b, j)`, respectively).

            The dual equivalence graph of `B` is defined to be the
            colored graph whose vertices are the elements of `B` of
            weight `0`, and whose edges of color `i` (for `i \in I`)
            connect pairs `\{ b, b' \}` such that `b'` is an
            `i`-elementary dual equivalence transformation of `b`.

            .. NOTE::

                This dual equivalence graph is a generalization of
                `\mathcal{G}\left(\mathcal{X}\right)` in [As2008]_
                Section 4 except we do not require
                `\varepsilon_i(b) = 0, 1` for all `i`.

            This definition can be generalized by choosing a subset `X`
            of the set of all vertices of `B` of weight `0`, and
            restricting the dual equivalence graph to the vertex set
            `X`.

            INPUT:

            - ``X`` -- (optional) the vertex set `X` (default:
              the whole set of vertices of ``self`` of weight `0`)
            - ``index_set`` -- (optional) the index set `I`
              (default: the whole index set of ``self``); this has
              to be a subset of the index set of ``self`` (as a list
              or tuple)
            - ``directed`` -- (default: ``True``) whether to have the
              dual equivalence graph be directed, where the head of
              an edge `b - b'` is `b` and the tail is
              `b' = f_{i-1} f_i e_{i-1} e_i b`)

            .. SEEALSO::

                :meth:`sage.combinat.partition.Partition.dual_equivalence_graph`

            EXAMPLES::

                sage: T = crystals.Tableaux(['A',3], shape=[2,2])
                sage: G = T.dual_equivalence_graph()
                sage: sorted(G.edges())
                [([[1, 3], [2, 4]], [[1, 2], [3, 4]], 2),
                 ([[1, 2], [3, 4]], [[1, 3], [2, 4]], 3)]
                sage: T = crystals.Tableaux(['A',4], shape=[3,2])
                sage: G = T.dual_equivalence_graph()
                sage: sorted(G.edges())
                [([[1, 3, 5], [2, 4]], [[1, 3, 4], [2, 5]], 4),
                 ([[1, 3, 5], [2, 4]], [[1, 2, 5], [3, 4]], 2),
                 ([[1, 3, 4], [2, 5]], [[1, 2, 4], [3, 5]], 2),
                 ([[1, 2, 5], [3, 4]], [[1, 3, 5], [2, 4]], 3),
                 ([[1, 2, 4], [3, 5]], [[1, 2, 3], [4, 5]], 3),
                 ([[1, 2, 3], [4, 5]], [[1, 2, 4], [3, 5]], 4)]

                sage: T = crystals.Tableaux(['A',4], shape=[3,1])
                sage: G = T.dual_equivalence_graph(index_set=[1,2,3])
                sage: G.vertices()
                [[[1, 3, 4], [2]], [[1, 2, 4], [3]], [[1, 2, 3], [4]]]
                sage: G.edges()
                [([[1, 3, 4], [2]], [[1, 2, 4], [3]], 2),
                 ([[1, 2, 4], [3]], [[1, 2, 3], [4]], 3)]

            TESTS::

                sage: T = crystals.Tableaux(['A',4], shape=[3,1])
                sage: G = T.dual_equivalence_graph(index_set=[2,3])
                sage: sorted(G.edges())
                [([[1, 2, 4], [3]], [[1, 2, 3], [4]], 3),
                 ([[2, 4, 5], [3]], [[2, 3, 5], [4]], 3)]
                sage: sorted(G.vertices())
                [[[1, 3, 4], [2]],
                 [[1, 2, 4], [3]],
                 [[2, 4, 5], [3]],
                 [[1, 2, 3], [4]],
                 [[2, 3, 5], [4]],
                 [[1, 1, 1], [5]],
                 [[1, 1, 5], [5]],
                 [[1, 5, 5], [5]],
                 [[2, 3, 4], [5]]]
            """
            if index_set is None:
                index_set = self.index_set()

            def wt_zero(x):
                for i in index_set:
                    if x.epsilon(i) != x.phi(i):
                        return False
                return True

            if X is None:
                X = [x for x in self if wt_zero(x)]
                checker = lambda x: True
            elif any(not wt_zero(x) for x in X):
                raise ValueError("the elements are not all weight 0")
            else:
                checker = lambda x: x in X

            edges = []
            for x in X:
                for k, i in enumerate(index_set[1:]):
                    im = index_set[k]
                    if x.epsilon(i) == 1 and x.epsilon(im) == 0:
                        y = x.e(i).e(im).f(i).f(im)
                        if checker(y):
                            edges.append([x, y, i])
            from sage.graphs.all import DiGraph
            G = DiGraph([X, edges],
                        format="vertices_and_edges",
                        immutable=True)
            if have_dot2tex():
                G.set_latex_options(
                    format="dot2tex",
                    edge_labels=True,
                    color_by_label=self.cartan_type()._index_set_coloring)
            return G
Esempio n. 40
0
        def digraph(self, subset=None, index_set=None):
            """
            Returns the DiGraph associated to ``self``.

            INPUT:

            - ``subset`` -- (Optional) A subset of vertices for
              which the digraph should be constructed

            - ``index_set`` -- (Optional) The index set to draw arrows

            EXAMPLES::

                sage: C = Crystals().example(5)
                sage: C.digraph()
                Digraph on 6 vertices

            The edges of the crystal graph are by default colored using blue for edge 1, red for edge 2,
            and green for edge 3::

                sage: C = Crystals().example(3)
                sage: G = C.digraph()
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            One may also overwrite the colors::

                sage: C = Crystals().example(3)
                sage: G = C.digraph()
                sage: G.set_latex_options(color_by_label = {1:"red", 2:"purple", 3:"blue"})
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            Or one may add colors to yet unspecified edges::

                sage: C = Crystals().example(4)
                sage: G = C.digraph()
                sage: C.cartan_type()._index_set_coloring[4]="purple"
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            Here is an example of how to take the top part up to a given depth of an infinite dimensional
            crystal::

                sage: C = CartanType(['C',2,1])
                sage: La = C.root_system().weight_lattice().fundamental_weights()
                sage: T = HighestWeightCrystal(La[0])
                sage: S = T.subcrystal(max_depth=3)
                sage: G = T.digraph(subset=S); G
                Digraph on 5 vertices
                sage: G.vertices()
                [(1/2*Lambda[0] + Lambda[1] - Lambda[2] - 1/2*delta, -1/2*Lambda[0] + Lambda[1] - 1/2*delta),
                (-Lambda[0] + 2*Lambda[1] - delta,), (Lambda[0] - 2*Lambda[1] + 2*Lambda[2] - delta,),
                (1/2*Lambda[0] - Lambda[1] + Lambda[2] - 1/2*delta, -1/2*Lambda[0] + Lambda[1] - 1/2*delta), (Lambda[0],)]

            Here is a way to construct a picture of a Demazure crystal using
            the ``subset`` option::

                sage: B = CrystalOfTableaux(['A',2], shape=[2,1])
                sage: C = CombinatorialFreeModule(QQ,B)
                sage: t = B.highest_weight_vector()
                sage: b = C(t)
                sage: D = B.demazure_operator(b,[2,1]); D
                B[[[1, 1], [2]]] + B[[[1, 2], [2]]] + B[[[1, 3], [2]]] + B[[[1, 1], [3]]] + B[[[1, 3], [3]]]
                sage: G = B.digraph(subset=D.support())
                sage: G.vertices()
                [[[1, 1], [2]], [[1, 2], [2]], [[1, 3], [2]], [[1, 1], [3]], [[1, 3], [3]]]
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            We can also choose to display particular arrows using the
            ``index_set`` option::

                sage: C = KirillovReshetikhinCrystal(['D',4,1], 2, 1)
                sage: G = C.digraph(index_set=[1,3])
                sage: len(G.edges())
                20
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            TODO: add more tests
            """
            from sage.graphs.all import DiGraph
            from sage.categories.highest_weight_crystals import HighestWeightCrystals
            d = {}
            if self in HighestWeightCrystals:
                f = lambda (u,v,label): ({})
            else:
                f = lambda (u,v,label): ({"backward":label ==0})

            # Parse optional arguments
            if subset is None:
                subset = self
            if index_set is None:
                index_set = self.index_set()

            for x in subset:
                d[x] = {}
                for i in index_set:
                    child = x.f(i)
                    if child is None or child not in subset:
                        continue
                    d[x][child]=i
            G = DiGraph(d)
            if have_dot2tex():
                G.set_latex_options(format="dot2tex",
                                    edge_labels = True,
                                    color_by_label = self.cartan_type()._index_set_coloring,
                                    edge_options = f)
            return G
Esempio n. 41
0
    def uncompactify(self):
        r"""
        Returns the tree obtained from self by splitting edges so that they
        are labelled by exactly one letter. The resulting tree is
        isomorphic to the suffix trie.

        EXAMPLES::

            sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree, SuffixTrie
            sage: abbab = Words("ab")("abbab")
            sage: s = SuffixTrie(abbab)
            sage: t = ImplicitSuffixTree(abbab)
            sage: t.uncompactify().is_isomorphic(s.to_digraph())
            True
        """
        tree = self.to_digraph(word_labels=True)
        newtree = DiGraph()
        newtree.add_vertices(range(tree.order()))
        new_node = tree.order() + 1
        for (u,v,label) in tree.edge_iterator():
            if len(label) == 1:
                newtree.add_edge(u,v)
            else:
                newtree.add_edge(u,new_node,label[0]);
                for w in label[1:-1]:
                    newtree.add_edge(new_node,new_node+1,w)
                    new_node += 1
                newtree.add_edge(new_node,v,label[-1])
                new_node += 1
        return newtree
Esempio n. 42
0
    def markov_chain_digraph(self, action = 'promotion', labeling = 'identity'):
        r"""
        Returns the digraph of the action of generalized promotion or tau on ``self``

        INPUT:

        - ``action`` -- 'promotion' or 'tau' (default: 'promotion')
        - ``labeling`` -- 'identity' or 'source' (default: 'identity')

        .. todo::

            - generalize this feature by accepting a family of operators as input
            - move up in some appropriate category

        This method creates a graph with vertices being the linear extensions of a given finite
        poset and an edge from `\pi` to `\pi'` if `\pi' = \pi \partial_i` where `\partial_i` is
        the promotion operator (see :meth:`promotion`) if ``action`` is set to ``promotion``
        and `\tau_i` (see :meth:`tau`) if ``action`` is set to ``tau``. The label of the edge
        is `i` (resp. `\pi_i`) if ``labeling`` is set to ``identity`` (resp. ``source``).

        EXAMPLES::

            sage: P = Poset(([1,2,3,4], [[1,3],[1,4],[2,3]]), linear_extension = True)
            sage: L = P.linear_extensions()
            sage: G = L.markov_chain_digraph(); G
            Looped multi-digraph on 5 vertices
            sage: sorted(G.vertices(), key = repr)
            [[1, 2, 3, 4], [1, 2, 4, 3], [1, 4, 2, 3], [2, 1, 3, 4], [2, 1, 4, 3]]
            sage: sorted(G.edges(), key = repr)
            [([1, 2, 3, 4], [1, 2, 3, 4], 4), ([1, 2, 3, 4], [1, 2, 4, 3], 2), ([1, 2, 3, 4], [1, 2, 4, 3], 3),
            ([1, 2, 3, 4], [2, 1, 4, 3], 1), ([1, 2, 4, 3], [1, 2, 3, 4], 3), ([1, 2, 4, 3], [1, 2, 4, 3], 4),
            ([1, 2, 4, 3], [1, 4, 2, 3], 2), ([1, 2, 4, 3], [2, 1, 3, 4], 1), ([1, 4, 2, 3], [1, 2, 3, 4], 1),
            ([1, 4, 2, 3], [1, 2, 3, 4], 2), ([1, 4, 2, 3], [1, 4, 2, 3], 3), ([1, 4, 2, 3], [1, 4, 2, 3], 4),
            ([2, 1, 3, 4], [1, 2, 4, 3], 1), ([2, 1, 3, 4], [2, 1, 3, 4], 4), ([2, 1, 3, 4], [2, 1, 4, 3], 2),
            ([2, 1, 3, 4], [2, 1, 4, 3], 3), ([2, 1, 4, 3], [1, 4, 2, 3], 1), ([2, 1, 4, 3], [2, 1, 3, 4], 2),
            ([2, 1, 4, 3], [2, 1, 3, 4], 3), ([2, 1, 4, 3], [2, 1, 4, 3], 4)]

            sage: G = L.markov_chain_digraph(labeling = 'source')
            sage: sorted(G.vertices(), key = repr)
            [[1, 2, 3, 4], [1, 2, 4, 3], [1, 4, 2, 3], [2, 1, 3, 4], [2, 1, 4, 3]]
            sage: sorted(G.edges(), key = repr)
            [([1, 2, 3, 4], [1, 2, 3, 4], 4), ([1, 2, 3, 4], [1, 2, 4, 3], 2), ([1, 2, 3, 4], [1, 2, 4, 3], 3),
            ([1, 2, 3, 4], [2, 1, 4, 3], 1), ([1, 2, 4, 3], [1, 2, 3, 4], 4), ([1, 2, 4, 3], [1, 2, 4, 3], 3),
            ([1, 2, 4, 3], [1, 4, 2, 3], 2), ([1, 2, 4, 3], [2, 1, 3, 4], 1), ([1, 4, 2, 3], [1, 2, 3, 4], 1),
            ([1, 4, 2, 3], [1, 2, 3, 4], 4), ([1, 4, 2, 3], [1, 4, 2, 3], 2), ([1, 4, 2, 3], [1, 4, 2, 3], 3),
            ([2, 1, 3, 4], [1, 2, 4, 3], 2), ([2, 1, 3, 4], [2, 1, 3, 4], 4), ([2, 1, 3, 4], [2, 1, 4, 3], 1),
            ([2, 1, 3, 4], [2, 1, 4, 3], 3), ([2, 1, 4, 3], [1, 4, 2, 3], 2), ([2, 1, 4, 3], [2, 1, 3, 4], 1),
            ([2, 1, 4, 3], [2, 1, 3, 4], 4), ([2, 1, 4, 3], [2, 1, 4, 3], 3)]

        The edges of the graph are by default colored using blue for
        edge 1, red for edge 2, green for edge 3, and yellow for edge 4::

            sage: view(G) #optional - dot2tex graphviz

        Alternatively, one may get the graph of the action of the ``tau`` operator::

            sage: G = L.markov_chain_digraph(action='tau'); G
            Looped multi-digraph on 5 vertices
            sage: sorted(G.vertices(), key = repr)
            [[1, 2, 3, 4], [1, 2, 4, 3], [1, 4, 2, 3], [2, 1, 3, 4], [2, 1, 4, 3]]
            sage: sorted(G.edges(), key = repr)
            [([1, 2, 3, 4], [1, 2, 3, 4], 2), ([1, 2, 3, 4], [1, 2, 4, 3], 3), ([1, 2, 3, 4], [2, 1, 3, 4], 1),
            ([1, 2, 4, 3], [1, 2, 3, 4], 3), ([1, 2, 4, 3], [1, 4, 2, 3], 2), ([1, 2, 4, 3], [2, 1, 4, 3], 1),
            ([1, 4, 2, 3], [1, 2, 4, 3], 2), ([1, 4, 2, 3], [1, 4, 2, 3], 1), ([1, 4, 2, 3], [1, 4, 2, 3], 3),
            ([2, 1, 3, 4], [1, 2, 3, 4], 1), ([2, 1, 3, 4], [2, 1, 3, 4], 2), ([2, 1, 3, 4], [2, 1, 4, 3], 3),
            ([2, 1, 4, 3], [1, 2, 4, 3], 1), ([2, 1, 4, 3], [2, 1, 3, 4], 3), ([2, 1, 4, 3], [2, 1, 4, 3], 2)]
            sage: view(G) #optional - dot2tex graphviz

        .. seealso:: :meth:`markov_chain_transition_matrix`, :meth:`promotion`, :meth:`tau`

        TESTS::

            sage: P = Poset(([1,2,3,4], [[1,3],[1,4],[2,3]]), linear_extension = True, facade = True)
            sage: L = P.linear_extensions()
            sage: G = L.markov_chain_digraph(labeling = 'source'); G
            Looped multi-digraph on 5 vertices
        """
        d = dict([x,dict([y,[]] for y in self)] for x in self)
        if action == 'promotion':
            R = range(self.poset().cardinality())
        else:
            R = range(self.poset().cardinality()-1)
        if labeling == 'source':
            for x in self:
                for i in R:
                    child = getattr(x, action)(i+1)
                    d[x][child]+=[self.poset().unwrap(x[i])]
        else:
            for x in self:
                for i in R:
                    child = getattr(x, action)(i+1)
                    d[x][child]+=[i+1]
        G = DiGraph(d)
        if have_dot2tex():
            G.set_latex_options(format="dot2tex", edge_labels = True, color_by_label = {1:"blue", 2:"red", 3:"green", 4:"yellow"})
            #G.set_latex_options(format="dot2tex", edge_labels = True, color_by_label = {1:"green", 2:"blue", 3:"brown", 4:"red"})
        return G
Esempio n. 43
0
        def dual_equivalence_graph(self, X=None, index_set=None, directed=True):
            r"""
            Return the dual equivalence graph indexed by ``index_set``
            on the subset ``X`` of ``self``.

            Let `b \in B` be an element of weight `0`, so `\varepsilon_j(b)
            = \varphi_j(b)` for all `j \in I`, where `I` is the indexing
            set. We say `b'` is an `i`-elementary dual equivalence
            transformation of `b` (where `i \in I`) if

            * `\varepsilon_i(b) = 1` and `\varepsilon_{i-1}(b) = 0`, and
            * `b' = f_{i-1} f_i e_{i-1} e_i b`.

            We can do the inverse procedure by interchanging `i` and `i-1`
            above.

            .. NOTE::

                If the index set is not an ordered interval, we let
                `i - 1` mean the index appearing before `i` in `I`.

            This definition comes from [Assaf08]_ Section 4 (where our
            `\varphi_j(b)` and `\varepsilon_j(b)` are denoted by
            `\epsilon(b, j)` and `-\delta(b, j)`, respectively).

            The dual equivalence graph of `B` is defined to be the
            colored graph whose vertices are the elements of `B` of
            weight `0`, and whose edges of color `i` (for `i \in I`)
            connect pairs `\{ b, b' \}` such that `b'` is an
            `i`-elementary dual equivalence transformation of `b`.

            .. NOTE::

                This dual equivalence graph is a generalization of
                `\mathcal{G}\left(\mathcal{X}\right)` in [Assaf08]_
                Section 4 except we do not require
                `\varepsilon_i(b) = 0, 1` for all `i`.

            This definition can be generalized by choosing a subset `X`
            of the set of all vertices of `B` of weight `0`, and
            restricting the dual equivalence graph to the vertex set
            `X`.

            INPUT:

            - ``X`` -- (optional) the vertex set `X` (default:
              the whole set of vertices of ``self`` of weight `0`)
            - ``index_set`` -- (optional) the index set `I`
              (default: the whole index set of ``self``); this has
              to be a subset of the index set of ``self`` (as a list
              or tuple)
            - ``directed`` -- (default: ``True``) whether to have the
              dual equivalence graph be directed, where the head of
              an edge `b - b'` is `b` and the tail is
              `b' = f_{i-1} f_i e_{i-1} e_i b`)

            .. SEEALSO::

                :meth:`sage.combinat.partition.Partition.dual_equivalence_graph`

            REFERENCES:

            .. [Assaf08] Sami Assaf. *A combinatorial realization of Schur-Weyl
               duality via crystal graphs and dual equivalence graphs*.
               FPSAC 2008, 141-152, Discrete Math. Theor. Comput. Sci. Proc.,
               AJ, Assoc. Discrete Math. Theor. Comput. Sci., (2008).
               :arxiv:`0804.1587v1`

            EXAMPLES::

                sage: T = crystals.Tableaux(['A',3], shape=[2,2])
                sage: G = T.dual_equivalence_graph()
                sage: sorted(G.edges())
                [([[1, 3], [2, 4]], [[1, 2], [3, 4]], 2),
                 ([[1, 2], [3, 4]], [[1, 3], [2, 4]], 3)]
                sage: T = crystals.Tableaux(['A',4], shape=[3,2])
                sage: G = T.dual_equivalence_graph()
                sage: sorted(G.edges())
                [([[1, 3, 5], [2, 4]], [[1, 3, 4], [2, 5]], 4),
                 ([[1, 3, 5], [2, 4]], [[1, 2, 5], [3, 4]], 2),
                 ([[1, 3, 4], [2, 5]], [[1, 2, 4], [3, 5]], 2),
                 ([[1, 2, 5], [3, 4]], [[1, 3, 5], [2, 4]], 3),
                 ([[1, 2, 4], [3, 5]], [[1, 2, 3], [4, 5]], 3),
                 ([[1, 2, 3], [4, 5]], [[1, 2, 4], [3, 5]], 4)]

                sage: T = crystals.Tableaux(['A',4], shape=[3,1])
                sage: G = T.dual_equivalence_graph(index_set=[1,2,3])
                sage: G.vertices()
                [[[1, 3, 4], [2]], [[1, 2, 4], [3]], [[1, 2, 3], [4]]]
                sage: G.edges()
                [([[1, 3, 4], [2]], [[1, 2, 4], [3]], 2),
                 ([[1, 2, 4], [3]], [[1, 2, 3], [4]], 3)]

            TESTS::

                sage: T = crystals.Tableaux(['A',4], shape=[3,1])
                sage: G = T.dual_equivalence_graph(index_set=[2,3])
                sage: sorted(G.edges())
                [([[1, 2, 4], [3]], [[1, 2, 3], [4]], 3),
                 ([[2, 4, 5], [3]], [[2, 3, 5], [4]], 3)]
                sage: sorted(G.vertices())
                [[[1, 3, 4], [2]],
                 [[1, 2, 4], [3]],
                 [[2, 4, 5], [3]],
                 [[1, 2, 3], [4]],
                 [[2, 3, 5], [4]],
                 [[1, 1, 1], [5]],
                 [[1, 1, 5], [5]],
                 [[1, 5, 5], [5]],
                 [[2, 3, 4], [5]]]
            """
            if index_set is None:
                index_set = self.index_set()

            def wt_zero(x):
                for i in index_set:
                    if x.epsilon(i) != x.phi(i):
                        return False
                return True

            if X is None:
                X = [x for x in self if wt_zero(x)]
                checker = lambda x: True
            elif any(not wt_zero(x) for x in X):
                raise ValueError("the elements are not all weight 0")
            else:
                checker = lambda x: x in X

            edges = []
            for x in X:
                for k, i in enumerate(index_set[1:]):
                    im = index_set[k]
                    if x.epsilon(i) == 1 and x.epsilon(im) == 0:
                        y = x.e(i).e(im).f(i).f(im)
                        if checker(y):
                            edges.append([x, y, i])
            from sage.graphs.all import DiGraph
            G = DiGraph([X, edges], format="vertices_and_edges", immutable=True)
            if have_dot2tex():
                G.set_latex_options(format="dot2tex", edge_labels=True,
                                    color_by_label=self.cartan_type()._index_set_coloring)
            return G
Esempio n. 44
0
        def digraph(self, subset=None, index_set=None):
            """
            Returns the DiGraph associated to ``self``.

            INPUT:

            - ``subset`` -- (Optional) A subset of vertices for
              which the digraph should be constructed

            - ``index_set`` -- (Optional) The index set to draw arrows

            EXAMPLES::

                sage: C = Crystals().example(5)
                sage: C.digraph()
                Digraph on 6 vertices

            The edges of the crystal graph are by default colored using blue for edge 1, red for edge 2,
            and green for edge 3::

                sage: C = Crystals().example(3)
                sage: G = C.digraph()
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            One may also overwrite the colors::

                sage: C = Crystals().example(3)
                sage: G = C.digraph()
                sage: G.set_latex_options(color_by_label = {1:"red", 2:"purple", 3:"blue"})
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            Or one may add colors to yet unspecified edges::

                sage: C = Crystals().example(4)
                sage: G = C.digraph()
                sage: C.cartan_type()._index_set_coloring[4]="purple"
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            Here is an example of how to take the top part up to a given depth of an infinite dimensional
            crystal::

                sage: C = CartanType(['C',2,1])
                sage: La = C.root_system().weight_lattice().fundamental_weights()
                sage: T = crystals.HighestWeight(La[0])
                sage: S = T.subcrystal(max_depth=3)
                sage: G = T.digraph(subset=S); G
                Digraph on 5 vertices
                sage: sorted(G.vertices(), key=str)
                [(-Lambda[0] + 2*Lambda[1] - delta,),
                 (1/2*Lambda[0] + Lambda[1] - Lambda[2] - 1/2*delta, -1/2*Lambda[0] + Lambda[1] - 1/2*delta),
                 (1/2*Lambda[0] - Lambda[1] + Lambda[2] - 1/2*delta, -1/2*Lambda[0] + Lambda[1] - 1/2*delta),
                 (Lambda[0] - 2*Lambda[1] + 2*Lambda[2] - delta,),
                 (Lambda[0],)]

            Here is a way to construct a picture of a Demazure crystal using
            the ``subset`` option::

                sage: B = crystals.Tableaux(['A',2], shape=[2,1])
                sage: C = CombinatorialFreeModule(QQ,B)
                sage: t = B.highest_weight_vector()
                sage: b = C(t)
                sage: D = B.demazure_operator(b,[2,1]); D
                B[[[1, 1], [2]]] + B[[[1, 2], [2]]] + B[[[1, 3], [2]]] + B[[[1, 1], [3]]] + B[[[1, 3], [3]]]
                sage: G = B.digraph(subset=D.support())
                sage: G.vertices()
                [[[1, 1], [2]], [[1, 2], [2]], [[1, 3], [2]], [[1, 1], [3]], [[1, 3], [3]]]
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            We can also choose to display particular arrows using the
            ``index_set`` option::

                sage: C = crystals.KirillovReshetikhin(['D',4,1], 2, 1)
                sage: G = C.digraph(index_set=[1,3])
                sage: len(G.edges())
                20
                sage: view(G, pdflatex=True, tightpage=True)  #optional - dot2tex graphviz

            TODO: add more tests
            """
            from sage.graphs.all import DiGraph
            from sage.categories.highest_weight_crystals import HighestWeightCrystals
            d = {}
            if self in HighestWeightCrystals:
                f = lambda u_v_label: ({})
            else:
                f = lambda u_v_label: ({"backward": u_v_label[2] == 0})

            # Parse optional arguments
            if subset is None:
                subset = self
            if index_set is None:
                index_set = self.index_set()

            for x in subset:
                d[x] = {}
                for i in index_set:
                    child = x.f(i)
                    if child is None or child not in subset:
                        continue
                    d[x][child]=i
            G = DiGraph(d)
            if have_dot2tex():
                G.set_latex_options(format="dot2tex",
                                    edge_labels = True,
                                    color_by_label = self.cartan_type()._index_set_coloring,
                                    edge_options = f)
            return G