Esempio n. 1
0
    def cyclegraph(self):
        r"""
        returns Digraph of all orbits of self mod `p`. For subschemes, only points on the subscheme whose
        image are also on the subscheme are in the digraph.

        OUTPUT:

        - a digraph

        EXAMPLES::

            sage: P.<x,y>=AffineSpace(GF(5),2)
            sage: H=Hom(P,P)
            sage: f=H([x^2-y,x*y+1])
            sage: f.cyclegraph()
            Looped digraph on 25 vertices

        ::

            sage: P.<x>=AffineSpace(GF(3^3,'t'),1)
            sage: H=Hom(P,P)
            sage: f=H([x^2-1])
            sage: f.cyclegraph()
            Looped digraph on 27 vertices

        ::

            sage: P.<x,y>=AffineSpace(GF(7),2)
            sage: X=P.subscheme(x-y)
            sage: H=Hom(X,X)
            sage: f=H([x^2,y^2])
            sage: f.cyclegraph()
            Looped digraph on 7 vertices
        """
        if self.domain() != self.codomain():
            raise NotImplementedError("Domain and Codomain must be equal")
        V = []
        E = []
        from sage.schemes.affine.affine_space import is_AffineSpace
        if is_AffineSpace(self.domain()) == True:
            for P in self.domain():
                V.append(str(P))
                Q = self(P)
                E.append([str(Q)])
        else:
            X = self.domain()
            for P in X.ambient_space():
                try:
                    XP = X.point(P)
                    V.append(str(XP))
                    Q = self(XP)
                    E.append([str(Q)])
                except TypeError:  # not on the scheme
                    pass
        from sage.graphs.digraph import DiGraph
        g = DiGraph(dict(zip(V, E)), loops=True)
        return g
Esempio n. 2
0
def random_orientation(G):
    r"""
    Return a random orientation of a graph `G`.

    An *orientation* of an undirected graph is a directed graph such that every
    edge is assigned a direction. Hence there are `2^m` oriented digraphs for a
    simple graph with `m` edges.

    INPUT:

    - ``G`` -- a Graph.

    EXAMPLES::

        sage: from sage.graphs.orientations import random_orientation
        sage: G = graphs.PetersenGraph()
        sage: D = random_orientation(G)
        sage: D.order() == G.order(), D.size() == G.size()
        (True, True)

    TESTS:

    Giving anything else than a Graph::

        sage: random_orientation([])
        Traceback (most recent call last):
        ...
        ValueError: the input parameter must be a Graph

    .. SEEALSO::

        - :meth:`~Graph.orientations`
    """
    from sage.graphs.graph import Graph
    if not isinstance(G, Graph):
        raise ValueError("the input parameter must be a Graph")

    D = DiGraph(data=[G.vertices(), []],
                format='vertices_and_edges',
                multiedges=G.allows_multiple_edges(),
                loops=G.allows_loops(),
                weighted=G.weighted(),
                pos=G.get_pos(),
                name="Random orientation of {}".format(G.name()) )
    if hasattr(G, '_embedding'):
        D._embedding = copy(G._embedding)

    from sage.misc.prandom import getrandbits
    rbits = getrandbits(G.size())
    for u,v,l in G.edge_iterator():
        if rbits % 2:
            D.add_edge(u, v, l)
        else:
            D.add_edge(v, u, l)
        rbits >>= 1
    return D
Esempio n. 3
0
def test_rm_sinks_sources_complex():
    G = digraphs.Path(5)
    G.add_path(list(range(5, 6)))
    G.add_edges([(0, 5), (4, 5)])
    T = DiGraph([(1, 0), (2, 0), (2, 1), (2, 4), (3, 0), (3, 1), (3, 2),
                 (4, 0), (4, 1), (4, 3), (5, 0), (5, 1), (5, 2), (5, 3),
                 (5, 4)])
    G, T = rm_sinks_and_sources(G, T, keep_T=True)
    assert set(G.removed) == set([0, 4, 5])
    assert set(T.removed) == set([0, 1, 5])
Esempio n. 4
0
def test_sinks_then_source_duplicates():
    G = DiGraph(
        [
            [0, 1, 2],  # wierzchołki
            [(1, 2)]  # krawędzie
        ],
        format='vertices_and_edges')
    ex = DiGraphExtended(G)
    ex.step('sink')
    assert ex.sources() == [1]
 def internal_vertex_multiplicity(self):
     """
     The number of different unlabeled DiGraphs (with different internal
     vertex labeling) that represent this KontsevichGraph.
     """
     return len(
         set([
             DiGraph(g, weighted=False, immutable=True)
             for g in self.internal_vertex_relabelings()
         ]))
Esempio n. 6
0
    def min_hasse_diagram(self):
        r"""
        Return Hasse diagram of the trace.

        OUTPUT:

        Directed graph of generator indexes.

        .. SEEALSO::

            :meth:`~sage.monoids.trace_monoid.TraceMonoidElement.hasse_digram`,
            :meth:`~sage.monoids.trace_monoid.TraceMonoidElement.naive_hasse_diagram`.

        EXAMPLES::

            sage: from sage.monoids.trace_monoid import TraceMonoid
            sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
            sage: M.<a,b,c,d> = TraceMonoid(I=I)
            sage: x = b * a * d * a * c * b
            sage: x.min_hasse_diagram()
            Digraph on 6 vertices
        """
        elements = self._flat_elements()
        elements.reverse()
        independence = self.parent()._independence
        reachable = dict()
        min = set()
        graph = DiGraph({})

        for i, x in enumerate(elements):
            reachable[i] = set()
            front = min.copy()
            while front:
                used = set()
                for j in list(front):
                    y = elements[j]
                    if (x, y) not in independence:
                        graph.add_edge(i, j)
                        reachable[i].add(j)
                        reachable[i].update(reachable[j])
                        if j in min:
                            min.remove(j)
                        used.add(j)
                forbidden = set(chain.from_iterable(reachable[v]
                                                    for v in used))
                front = set(
                    dest
                    for _, dest in graph.outgoing_edges(front, labels=False))
                front = front - forbidden

            min.add(i)

        length = len(elements)
        graph.relabel(length - 1 - i for i in range(length))
        return graph
Esempio n. 7
0
    def Circulant(self, n, integers):
        r"""
        Returns a circulant digraph on `n` vertices from a set of integers.

        INPUT:

        - ``n`` (integer) -- number of vertices.

        - ``integers`` -- the list of integers such that there is an edge from
          `i` to `j` if and only if ``(j-i)%n in integers``.

        EXAMPLE::

            sage: digraphs.Circulant(13,[3,5,7])
            Circulant graph ([3, 5, 7]): Digraph on 13 vertices

        TESTS::

            sage: digraphs.Circulant(13,[3,5,7,"hey"])
            Traceback (most recent call last):
            ...
            ValueError: The list must contain only relative integers.
            sage: digraphs.Circulant(-2,[3,5,7,3])
            Traceback (most recent call last):
            ...
            ValueError: n must be a positive integer
            sage: digraphs.Circulant(3,[3,5,7,3.4])
            Traceback (most recent call last):
            ...
            ValueError: The list must contain only relative integers.
        """
        from sage.graphs.graph_plot import _circle_embedding
        from sage.rings.integer_ring import ZZ

        # Bad input and loops
        loops = False
        if not n in ZZ or n <= 0:
            raise ValueError("n must be a positive integer")

        for i in integers:
            if not i in ZZ:
                raise ValueError(
                    "The list must contain only relative integers.")
            if (i % n) == 0:
                loops = True

        G = DiGraph(n,
                    name="Circulant graph (" + str(integers) + ")",
                    loops=loops)

        _circle_embedding(G, range(n))
        for v in range(n):
            G.add_edges([(v, (v + j) % n) for j in integers])

        return G
Esempio n. 8
0
        def digraph(self):
            r"""
            Return the :class:`DiGraph` associated to ``self``.

            EXAMPLES::

                sage: B = crystals.Letters(['A', [1,3]])
                sage: G = B.digraph(); G
                Multi-digraph on 6 vertices
                sage: Q = crystals.Letters(['Q',3])
                sage: G = Q.digraph(); G
                Multi-digraph on 3 vertices
                sage: G.edges()
                [(1, 2, -1), (1, 2, 1), (2, 3, -2), (2, 3, 2)]

            The edges of the crystal graph are by default colored using
            blue for edge 1, red for edge 2, green for edge 3, and dashed with
            the corresponding color for barred edges. Edge 0 is dotted black::

                sage: view(G)  # optional - dot2tex graphviz, not tested (opens external window)
            """
            from sage.graphs.digraph import DiGraph
            from sage.misc.latex import LatexExpr
            from sage.combinat.root_system.cartan_type import CartanType

            G = DiGraph(multiedges=True)
            G.add_vertices(self)
            for i in self.index_set():
                for x in G:
                    y = x.f(i)
                    if y is not None:
                        G.add_edge(x, y, i)

            def edge_options(data):
                u, v, l = data
                edge_opts = {'edge_string': '->', 'color': 'black'}
                if l > 0:
                    edge_opts['color'] = CartanType._colors.get(l, 'black')
                    edge_opts['label'] = LatexExpr(str(l))
                elif l < 0:
                    edge_opts['color'] = "dashed," + CartanType._colors.get(
                        -l, 'black')
                    edge_opts['label'] = LatexExpr("\\overline{%s}" % str(-l))
                else:
                    edge_opts['color'] = "dotted," + CartanType._colors.get(
                        l, 'black')
                    edge_opts['label'] = LatexExpr(str(l))
                return edge_opts

            G.set_latex_options(format="dot2tex",
                                edge_labels=True,
                                edge_options=edge_options)

            return G
Esempio n. 9
0
        def bhz_poset(self):
            r"""
            Return the Bergeron-Hohlweg-Zabrocki partial order on the Coxeter
            group.

            This is a partial order on the elements of a finite
            Coxeter group `W`, which is distinct from the Bruhat
            order, the weak order and the shard intersection order. It
            was defined in [BHZ2005]_.

            This partial order is not a lattice, as there is no unique
            maximal element. It can be succintly defined as follows.

            Let `u` and `v` be two elements of the Coxeter group `W`. Let
            `S(u)` be the support of `u`. Then `u \leq v` if and only
            if `v_{S(u)} = u` (here `v = v^I v_I` denotes the usual
            parabolic decomposition with respect to the standard parabolic
            subgroup `W_I`).

            .. SEEALSO::

                :meth:`bruhat_poset`, :meth:`shard_poset`, :meth:`weak_poset`

            EXAMPLES::

                sage: W = CoxeterGroup(['A',3], base_ring=ZZ)
                sage: P = W.bhz_poset(); P
                Finite poset containing 24 elements
                sage: P.relations_number()
                103
                sage: P.chain_polynomial()
                34*q^4 + 90*q^3 + 79*q^2 + 24*q + 1
                sage: len(P.maximal_elements())
                13
            """
            from sage.graphs.digraph import DiGraph
            from sage.combinat.posets.posets import Poset

            def covered_by(ux, vy):
                u, iu, Su = ux
                v, iv, Sv = vy
                if len(Sv) != len(Su) + 1:
                    return False
                if not all(u in Sv for u in Su):
                    return False
                return all((v * iu).has_descent(x, positive=True) for x in Su)

            vertices = [(u, u.inverse(),
                         tuple(set(u.reduced_word_reverse_iterator())))
                        for u in self]
            dg = DiGraph([vertices, covered_by])
            dg.relabel(lambda x: x[0])
            return Poset(dg, cover_relations=True)
Esempio n. 10
0
    def cyclegraph(self):
        r"""
        Return the digraph of all orbits of this morphism mod `p`.

        For subschemes, only points on the subscheme whose
        image are also on the subscheme are in the digraph.

        OUTPUT: a digraph

        EXAMPLES::

            sage: P.<x,y> = AffineSpace(GF(5), 2)
            sage: f = DynamicalSystem_affine([x^2-y, x*y+1])
            sage: f.cyclegraph()
            Looped digraph on 25 vertices

        ::

            sage: P.<x> = AffineSpace(GF(3^3, 't'), 1)
            sage: f = DynamicalSystem_affine([x^2-1])
            sage: f.cyclegraph()
            Looped digraph on 27 vertices

        ::

            sage: P.<x,y> = AffineSpace(GF(7), 2)
            sage: X = P.subscheme(x-y)
            sage: f = DynamicalSystem_affine([x^2, y^2], domain=X)
            sage: f.cyclegraph()
            Looped digraph on 7 vertices
        """
        V = []
        E = []
        from sage.schemes.affine.affine_space import is_AffineSpace
        if is_AffineSpace(self.domain()) == True:
            for P in self.domain():
                V.append(str(P))
                Q = self(P)
                E.append([str(Q)])
        else:
            X = self.domain()
            for P in X.ambient_space():
                try:
                    XP = X.point(P)
                    V.append(str(XP))
                    Q = self(XP)
                    E.append([str(Q)])
                except TypeError:  # not on the scheme
                    pass
        from sage.graphs.digraph import DiGraph
        g = DiGraph(dict(zip(V, E)), loops=True)
        return g
Esempio n. 11
0
    def stanley_symm_poly_weight(self, w):
        r"""
        Return the weight of `w`, to be used in the definition of
        Stanley symmetric functions.

        INPUT:

        - ``w`` -- a Pieri factor for this type

        For type `D`, this weight involves
        the number of components of the complement of the support of
        an element, where we consider `0` and `1` to be one node -- if `1`
        is in the support, then we pretend `0` in the support, and vice
        versa.  Similarly with `n-1` and `n`.  We also consider `0` and
        `1`, `n-1` and `n` to be one node for the purpose of counting
        components of the complement (as if the Dynkin diagram were
        that of type `C`).

        Type D Stanley symmetric polynomial weights are still
        conjectural.  The given weight comes from conditions on
        elements of the affine Fomin-Stanley subalgebra, but work is
        needed to show this weight is correct for affine Stanley
        symmetric functions -- see [LSS2009, Pon2010]_ for details.

        EXAMPLES::

            sage: W = WeylGroup(['D', 5, 1])
            sage: PF = W.pieri_factors()
            sage: PF.stanley_symm_poly_weight(W.from_reduced_word([5,2,1]))
            0
            sage: PF.stanley_symm_poly_weight(W.from_reduced_word([5,2,1,0]))
            0
            sage: PF.stanley_symm_poly_weight(W.from_reduced_word([5,2]))
            1
            sage: PF.stanley_symm_poly_weight(W.from_reduced_word([]))
            0

            sage: W = WeylGroup(['D',7,1])
            sage: PF = W.pieri_factors()
            sage: PF.stanley_symm_poly_weight(W.from_reduced_word([2,4,6]))
            2
        """
        ct = w.parent().cartan_type()
        support = set(w.reduced_word())
        n = w.parent().n
        if 1 in support or 0 in support:
            support = support.union(set([1])).difference(set([0]))
        if n in support or n - 1 in support:
            support = support.union(set([n - 2])).difference(set([n - 1]))
        support_complement = set(range(1, n - 1)).difference(support)
        return DiGraph(DynkinDiagram(ct)).subgraph(
            support_complement).connected_components_number() - 1
    def as_graph(self):
        r"""
        Return the graph associated to self
        """
        from sage.graphs.digraph import DiGraph

        G = DiGraph(multiedges=True, loops=True)
        d = self.degree()
        g = [self.g_tuple(i) for i in range(4)]
        for i in range(d):
            for j in range(4):
                G.add_edge(i, g[j][i], j)
        return G
Esempio n. 13
0
def directed_graph_has_odd_automorphism(g):
    n = len(g)
    edges = g.edges()
    G = DiGraph([list(range(n)), edges])
    for sigma in G.automorphism_group().gens(
    ):  # NOTE: it suffices to check generators
        edge_permutation = [
            tuple([sigma(edge[0]), sigma(edge[1])]) for edge in edges
        ]
        index_permutation = [edges.index(e) for e in edge_permutation]
        if selection_sort(index_permutation) == -1:
            return True
    return False
Esempio n. 14
0
    def stanley_symm_poly_weight(self, w):
        r"""
        Return the weight of a Pieri factor to be used in the definition of
        Stanley symmetric functions.

        For type B, this weight involves the number of components of
        the complement of the support of an element, where we consider
        0 and 1 to be one node -- if 1 is in the support, then we
        pretend 0 in the support, and vice versa.  We also consider 0
        and 1 to be one node for the purpose of counting components of
        the complement (as if the Dynkin diagram were that of type C).
        Let n be the rank of the affine Weyl group in question (if
        type ``['B',k,1]`` then we have n = k+1).  Let ``chi(v.length() < n-1)``
        be the indicator function that is 1 if the length of v is
        smaller than n-1, and 0 if the length of v is greater than or
        equal to n-1.  If we call ``c'(v)`` the number of components of
        the complement of the support of v, then the type B weight is
        given by ``weight = c'(v) - chi(v.length() < n-1)``.

        EXAMPLES::

            sage: W = WeylGroup(['B',5,1])
            sage: PF = W.pieri_factors()
            sage: PF.stanley_symm_poly_weight(W.from_reduced_word([0,3]))
            1
            sage: PF.stanley_symm_poly_weight(W.from_reduced_word([0,1,3]))
            1
            sage: PF.stanley_symm_poly_weight(W.from_reduced_word([2,3]))
            1
            sage: PF.stanley_symm_poly_weight(W.from_reduced_word([2,3,4,5]))
            0
            sage: PF.stanley_symm_poly_weight(W.from_reduced_word([0,5]))
            0
            sage: PF.stanley_symm_poly_weight(W.from_reduced_word([2,4,5,4,3,0]))
            -1
            sage: PF.stanley_symm_poly_weight(W.from_reduced_word([4,5,4,3,0]))
            0
        """
        ct = w.parent().cartan_type()
        support = set(w.reduced_word())
        if 1 in support or 0 in support:
            support_complement = set(
                ct.index_set()).difference(support).difference(set([0, 1]))
        else:
            support_complement = set(
                ct.index_set()).difference(support).difference(set([0]))
        return DiGraph(DynkinDiagram(ct)).subgraph(
            support_complement,
            algorithm="delete").connected_components_number() - 1
Esempio n. 15
0
def tournament_iterator(i, cycles):
    '''Iterator po grafach o jednym, lub co najmniej dwóch cyklach skierowanych
    (w zależności od parametru cycles).

    :param i: Int
        Liczba wierzchołków grafu
    :param cycles: string
        'one_cycle' lub 'more_cycles'
    :return: DiGraph
        Kolejne grafy skierowane.
    '''
    file = open(PATH + "/../tournaments/" + cycles + "/%d.dig6" % i, 'r')
    lines = file.readlines()
    for line in lines:
        yield DiGraph(line, format="dig6")
Esempio n. 16
0
def undirected_to_directed_graph_coefficient(undirected_graph, directed_graph):
    g = Graph(undirected_graph.edges())
    h = Graph(directed_graph.edges())
    are_isomorphic, sigma = g.is_isomorphic(h, certificate=True)
    assert are_isomorphic
    edges = directed_graph.edges()
    edge_permutation = [
        edges.index((sigma[a], sigma[b])) if
        (sigma[a], sigma[b]) in edges else edges.index((sigma[b], sigma[a]))
        for (a, b) in undirected_graph.edges()
    ]
    sign = selection_sort(edge_permutation)
    multiplicity = len(g.automorphism_group()) // len(
        DiGraph(directed_graph.edges()).automorphism_group())
    return sign * multiplicity
    def plot(self, **kwargs):
        """
        Return a graphics object representing the Kontsevich graph.

        INPUT:

        - ``edge_labels`` (boolean, default True) -- if True, show edge labels.
        - ``indices`` (boolean, default False) -- if True, show indices as
          edge labels instead of L and R; see :meth:`._latex_`.
        - ``upright`` (boolean, default False) -- if True, try to plot the
          graph with the ground vertices on the bottom and the rest on top.
        """
        if not 'edge_labels' in kwargs:
            kwargs['edge_labels'] = True  # show edge labels by default
        if 'indices' in kwargs:
            del kwargs['indices']
            KG = DiGraph(self)
            for (k, e) in enumerate(self.edges()):
                KG.delete_edge(e)
                KG.add_edge((e[0], e[1], chr(97 + k)))
            return KG.plot(**kwargs)
        if len(self.ground_vertices()) == 2 and 'upright' in kwargs:
            del kwargs['upright']
            kwargs['save_pos'] = True
            DiGraph.plot(self, **kwargs)
            positions = self.get_pos()
            # translate F to origin:
            F_pos = vector(positions[self.ground_vertices()[0]])
            for p in positions:
                positions[p] = list(vector(positions[p]) - F_pos)
            # scale F - G distance to 1:
            G_len = abs(vector(positions[self.ground_vertices()[1]]))
            for p in positions:
                positions[p] = list(vector(positions[p]) / G_len)
            # rotate the vector F - G to (1,0)
            from math import atan2
            theta = -atan2(positions[self.ground_vertices()[1]][1],
                           positions[self.ground_vertices()[1]][0])
            for p in positions:
                positions[p] = list(
                    matrix([[cos(theta), -(sin(theta))],
                            [sin(theta), cos(theta)]]) * vector(positions[p]))
            # flip if most things are below the x-axis:
            if len([(x, y) for (x, y) in positions.values() if y < 0]) / len(
                    self.internal_vertices()) > 0.5:
                for p in positions:
                    positions[p] = [positions[p][0], -positions[p][1]]
        return DiGraph.plot(self, **kwargs)
    def internal_vertex_relabelings(self):
        """
        Yield all possible internal vertex relabelings as Kontsevich graphs.
        """
        assert self.internal_vertices_normalized(), \
               "Internal vertices should be normalized."

        def all_of_them():
            for sigma in SymmetricGroup(self.internal_vertices()):
                yield self.relabel(lambda v: sigma(v) \
                                             if v in self.internal_vertices() \
                                             else v, inplace=False)

        return filter_unique(
            all_of_them(),
            key=lambda KG: DiGraph(KG, weighted=True, immutable=True))
Esempio n. 19
0
    def _construct_BGG_graph(self):
        """Find all the arrows in the BGG Graph.

        There is an arrow w->w' if len(w')=len(w)+1 and w' = t.w for some t in T.
        """
        self.arrows = []
        for w in self.reduced_words:
            for t in self.T:
                product_word = self.reduced_word_dic_reversed[
                    t * self.reduced_word_dic[w]]
                if len(product_word) == len(w) + 1:
                    self.arrows += [(w, product_word)]
        self.arrows = sorted(
            self.arrows,
            key=lambda t: len(t[0]))  # sort the arrows by the word length
        self.graph = DiGraph(self.arrows)
Esempio n. 20
0
def directed_graph_canonicalize(g):
    n = len(g)
    edges = g.edges()
    G, sigma = DiGraph([list(range(n)),
                        edges]).canonical_label(certificate=True)
    new_edges = list(G.edges(labels=False))
    edge_permutation = [
        tuple([sigma[edge[0]], sigma[edge[1]]]) for edge in edges
    ]
    index_permutation = [new_edges.index(e) for e in edge_permutation]
    undo_canonicalize = [0] * n
    for k, v in sigma.items():
        undo_canonicalize[v] = k
    return DirectedGraph(
        n,
        list(new_edges)), undo_canonicalize, selection_sort(index_permutation)
Esempio n. 21
0
    def __init__(self,
                 edge_set,
                 vertex_sizes,
                 num_locs,
                 initial_distribution=None):
        if (initial_distribution is None):
            self.even_dist = True
        else:
            self.even_dist = False
            self.initial_distribution = initial_distribution
        self.vertex_sizes = vertex_sizes
        assert len(edge_set.values()) > 0
        assert len(list(edge_set.values())[0]) == 3
        blocks = [k for (_, k, _) in edge_set.values()]
        firsts = [k_0[0] for k_0 in blocks]
        # Ensure that all elements are assigned to at most once
        # Assumes that all operations are assignments, which precludes
        # in-place operations
        assert len(set(firsts)) == len(firsts)
        self.hypergraph = IS(blocks)
        # Make sure the big vertex list only includes vertices in the
        # edge set
        ground_set = set(self.hypergraph.ground_set())
        assert ground_set == (ground_set
                              | set(vertex_sizes[0] + vertex_sizes[1] +
                                    vertex_sizes[2] + vertex_sizes[3]))
        self.edge_set = edge_set
        lhs = {l[0]: edge for (edge, (_, l, _)) in self.edge_set.items()}
        partial_order = {k: set([]) for k in self.edge_set.keys()}
        for name, (_, var_s, _) in self.edge_set.items():
            for i in var_s[1:]:
                try:
                    if lhs[i] != name:
                        partial_order[name].add(lhs[i])
                except KeyError:
                    partial_order[name].add('_begin_')
        self.partial_order = DiGraph(partial_order).reverse()
        vertex_set = self.hypergraph.ground_set()

        self.output_size_calculators = {
            2: {
                'add': self.add_output_size,
                'mul': self.mul_output_size
            }
        }
        self.vertices = {}
        self.init_vertices(vertex_set)
Esempio n. 22
0
def projection_graph(G, proj_fn, filename=None, verbose=False):
    r"""
    Return the image of a graph under a function on vertices.

    INPUT:

    - ``G`` -- graph
    - ``proj_fn`` -- function
    - ``filename`` -- integer (default:``None``), save the graph to this pdf
      filename if filename is not None
    - ``verbose`` -- bool (default:``False``), print a table of data about the
      projection

    EXAMPLES::

        sage: from slabbe.graph import projection_graph
        sage: g = graphs.PetersenGraph()
        sage: g.vertices()
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        sage: f = lambda i: i % 5
        sage: projection_graph(g, f)
        Looped multi-digraph on 5 vertices

    With verbose information::

        sage: projection_graph(g, lambda i:i%4, verbose=True)
          Number of vertices   Projected vertices
        +--------------------+--------------------+
          2                    3
          2                    2
          3                    1
          3                    0
        Looped multi-digraph on 4 vertices
    """
    edges = set((proj_fn(A),proj_fn(B)) for A,B,_ in G.edges())
    G_proj = DiGraph(edges, format='list_of_edges', loops=True, multiedges=True)
    if verbose:
        d = dict(Counter(proj_fn(s) for s in G.vertices()))
        rows = [(value, key) for key,value in d.iteritems()]
        rows.sort(reverse=True,key=lambda row:row[1])
        header_row = ['Number of vertices', 'Projected vertices']
        from sage.misc.table import table
        print table(rows=rows, header_row=header_row)
    if filename:
        from slabbe import TikzPicture
        print TikzPicture.from_graph(G_proj, prog='dot').pdf(filename)
    return G_proj
Esempio n. 23
0
    def YoungsLatticePrincipalOrderIdeal(lam):
        """
        Return the principal order ideal of the
        partition `lam` in Young's Lattice.

        INPUT:

        - ``lam`` -- a partition

        EXAMPLES::

            sage: P = Posets.YoungsLatticePrincipalOrderIdeal(Partition([2,2]))
            sage: P
            Finite lattice containing 6 elements
            sage: P.cover_relations()
            [[[], [1]],
             [[1], [1, 1]],
             [[1], [2]],
             [[1, 1], [2, 1]],
             [[2], [2, 1]],
             [[2, 1], [2, 2]]]
        """
        from sage.misc.flatten import flatten
        from sage.combinat.partition import Partition

        def lower_covers(l):
            """
            Nested function returning those partitions obtained
            from the partition `l` by removing
            a single cell.
            """
            return [l.remove_cell(c[0], c[1]) for c in l.removable_cells()]

        def contained_partitions(l):
            """
            Nested function returning those partitions contained in
            the partition `l`
            """
            if l == Partition([]):
                return l
            return flatten(
                [l, [contained_partitions(m) for m in lower_covers(l)]])

        ideal = list(set(contained_partitions(lam)))
        H = DiGraph(dict([[p, lower_covers(p)] for p in ideal]))
        return LatticePoset(H.reverse())
def plot_graphs(file_in,
                dir_out,
                compressibility=None,
                path_len=None,
                compr_path_diff=None):
    '''Funkcja rysująca grafy, które zostały zapisane w pliku 'file_in' i
    spełniające kryteria określone przez ostatnie trzy parametry opisane
    poniżej.

    :param file_in: string
        Ścieżka do pliku, z którego pobierane są grafy.
    :param dir_out: string
        Ścieżka do katalogu, w którym zostaną zapisane rysunki.
    :param compressibility: list
        Lista określająca, jaką kompresowalność muszą mieć grafy, żeby zostały
        narysowane. Jeżeli równe 'None', to brak ograniczeń.
    :param path_len: list
        Lista określająca, jaką długość najdłuższej ścieżki muszą mieć grafy,
        żeby zostały narysowane. Jeżeli równe 'None', to brak ograniczeń.
    :param compr_path_diff: list
        Lista określająca, jaką różnicę pomiędzy kompresowalnością, a długośćią
        najdłuższej ścieżki muszą mieć grafy, żeby zostały narysowane. Jeżeli
        równe 'None', to brak ograniczeń.
    '''
    file = open(file_in, 'r')
    i = 0
    if dir_out[-1] != '/':
        dir_out += "/"
    for line in file:
        graph, comp, path = line.split()
        comp = int(comp)
        path = int(path)
        if compressibility is not None:
            if comp not in compressibility:
                continue
        if path_len is not None:
            if path not in path_len:
                continue
        if compr_path_diff is not None:
            if comp - path not in compr_path_diff:
                continue
        p = DiGraph(graph).plot(title="Longest path: %d, Compressibility: %d" %
                                (path, comp))
        p.save(dir_out + "%d.png" % i)
        i += 1
Esempio n. 25
0
    def cyclegraph(self):
        r"""
        Return the digraph of all orbits of this morphism mod `p`.

        OUTPUT: a digraph

        EXAMPLES::

            sage: P.<a,b,c,d> = ProductProjectiveSpaces(GF(3), [1,1])
            sage: f = DynamicalSystem_projective([a^2,b^2,c^2,d^2], domain=P)
            sage: f.cyclegraph()
            Looped digraph on 16 vertices

        ::

            sage: P.<a,b,c,d> = ProductProjectiveSpaces(GF(5), [1,1])
            sage: f = DynamicalSystem_projective([a^2,b^2,c,d], domain=P)
            sage: f.cyclegraph()
            Looped digraph on 36 vertices

        ::

            sage: P.<a,b,c,d,e> = ProductProjectiveSpaces(GF(2), [1,2])
            sage: f = DynamicalSystem_projective([a^2,b^2,c,d,e], domain=P)
            sage: f.cyclegraph()
            Looped digraph on 21 vertices

        .. TODO:: Dynamical systems for subschemes of product projective spaces needs work.
                  Thus this is not implemented for subschemes.
        """
        V = []
        E = []
        from sage.schemes.product_projective.space import is_ProductProjectiveSpaces
        if is_ProductProjectiveSpaces(self.domain()) == True:
            for P in self.domain():
                V.append(str(P))
                Q = self(P)
                E.append([str(Q)])
        else:
            raise NotImplementedError(
                "Cyclegraph for product projective spaces not implemented for subschemes"
            )
        from sage.graphs.digraph import DiGraph
        g = DiGraph(dict(zip(V, E)), loops=True)
        return g
def operation_digraph(structure,
                      operation,
                      render=False,
                      file_name='operation_digraph.asy',
                      labels=True,
                      size=100):
    """
    A digraph corresponding to a unary operation.

    Note that one might need to play with the `order` setting to get a decent image.

    Args:
        structure (AlgebraicStructure): The algebraic structure used in the construction of the complex.
        operation (function): The operation used in the construction of the complex.
        render (bool): Whether the digraph should be given as asymptote vector graphics source code.
        file_name (str): The name of the file generated is `render` is True.
        labels (bool): Whether to label elements in the asymptote source.
        order (int): The order of the resulting image.

    Returns:
        Digraph: The corresponding operation digraph.
    """

    m = structure.action_matrix(operation)
    if render == True:
        order = structure.order
        file = open(file_name, 'w')
        file.write('size({});'.format(size) + '\n' + 'dotfactor=10;')
        file.write('for(int i=0; i<{}; ++i){{'.format(order) + '\n' +
                   'dot(dir(90-360/{}*i));}}'.format(order) + '\n')
        elem_lis = structure.canonical_order
        for i in range(order):
            if labels:
                file.write('label(\"${}$\",1.2*dir(90-360/{}*{}));'.format(
                    structure.element_names[elem_lis[i]], order, i) + '\n')
            if list(m[i]).index(1) == i:
                file.write(
                    'draw(dir(90-360/{0}*{1})..1.35*dir(90-360/{0}*{1})..cycle,MidArcArrow);'
                    .format(order, i) + '\n')
            else:
                file.write(
                    'draw(dir(90-360/{0}*{1})..dir(90-360/{0}*{2}),MidArrow);'.
                    format(order, i,
                           list(m[i]).index(1)) + '\n')
    return DiGraph(m)
Esempio n. 27
0
 def quiver_v2(self):
     #if hasattr(self, "_quiver_cache"):
     #    return self._quiver_cache
     from sage.combinat.subset import Subsets
     from sage.graphs.digraph import DiGraph
     Q = DiGraph(multiedges=True)
     Q.add_vertices(self.j_transversal())
     g = self.associated_graph()
     for U in Subsets(g.vertices()):
         for W in Subsets(U):
             h = g.subgraph(U.difference(W))
             n = h.connected_components_number() - 1
             if n > 0:
                 u = self.j_class_representative(self.j_class_index(self(''.join(U))))
                 w = self.j_class_representative(self.j_class_index(self(''.join(W))))
                 for i in range(n):
                     Q.add_edge(w, u, i)
     return Q
Esempio n. 28
0
def formality_graph_has_odd_automorphism(g):
    n = len(g)
    edges = g.edges()
    partition = [[v] for v in range(g.num_ground_vertices())] + [
        list(
            range(g.num_ground_vertices(),
                  g.num_ground_vertices() + g.num_aerial_vertices()))
    ]
    G = DiGraph([list(range(n)), edges])
    for sigma in G.automorphism_group(partition=partition).gens(
    ):  # NOTE: it suffices to check generators
        edge_permutation = [
            tuple([sigma(edge[0]), sigma(edge[1])]) for edge in edges
        ]
        index_permutation = [edges.index(e) for e in edge_permutation]
        if selection_sort(index_permutation) == -1:
            return True
    return False
Esempio n. 29
0
def shard_preorder_graph(runs):
    """
    Return the preorder attached to a tuple of decreasing runs.

    This is a directed graph, whose vertices correspond to the runs.

    There is an edge from a run `R` to a run `S` if `R` is before `S`
    in the list of runs and the two intervals defined by the initial and
    final indices of `R` and `S` overlap.

    This only depends on the initial and final indices of the runs.
    For this reason, this input can also be given in that shorten way.

    INPUT:

    - a tuple of tuples, the runs of a permutation, or

    - a tuple of pairs `(i,j)`, each one standing for a run from `i` to `j`.

    OUTPUT:

    a directed graph, with vertices labelled by integers

    EXAMPLES::

        sage: from sage.combinat.shard_order import shard_preorder_graph
        sage: s = Permutation([2,8,3,9,6,4,5,1,7])
        sage: def cut(lr):
        ....:     return tuple((r[0], r[-1]) for r in lr)
        sage: shard_preorder_graph(cut(s.decreasing_runs()))
        Digraph on 5 vertices
        sage: s = Permutation([9,4,3,2,8,6,5,1,7])
        sage: P = shard_preorder_graph(s.decreasing_runs())
        sage: P.is_isomorphic(digraphs.TransitiveTournament(3))
        True
    """
    N = len(runs)
    dg = DiGraph(N)
    dg.add_edges((i, j) for i in range(N - 1)
                 for j in range(i + 1, N)
                 if runs[i][-1] < runs[j][0] and runs[j][-1] < runs[i][0])
    return dg
Esempio n. 30
0
def tournament_with_one_cycle(k, sink):
    '''Zwraca turniej z dokładnie jednym cyklem. Warto zauważyć
    że taki turniej będzie albo cyklem C_3, albo powstaje poprzez
    dodawanie do C_3 kolejnych wierzchołków, które w danym momencie
    będą źródłami bądź ujściami ([1], komentarz pod Algorytmem 2).

    :param k: Int
        Liczba wierzchołków w turnieju
    :param sink: Bool array
        Kontroluje, w jaki sposób mają być skierowane kolejne krawędzie.
        Jeżeli dirs[i] == True, to wszystkie krawędzie łączące wierzchołek
        i z wierzchołkami o niższych indeksach, będą skierowane w stronę i
        (tzn. i wtedy będzie ujściem).
        Rozmiar dirs powinien być równy k - 3
    :return: DiGraph
        Turniej o k wierzchołkach, zawierający dokładnie jeden cykl.
    '''
    if not isinstance(k, int) or k < 3:
        raise ValueError("k musi być liczbą naturalną większą lub równą 3")
    if len(sink) != k - 3:
        raise ValueError("Długość tablicy sink musi być równa k-3")

    T = DiGraph()
    T.add_cycle([0, 2, 1])

    def add_source(G, v):
        vertices = G.vertices()
        for u in vertices:
            G.add_edge(v, u)

    def add_sink(G, v):
        vertices = G.vertices()
        for u in vertices:
            G.add_edge(u, v)

    for i, flag in enumerate(sink):
        if flag:
            add_sink(T, i + 3)
        else:
            add_source(T, i + 3)

    return T