Ticket #13961: trac_13961-move_stuff_around.patch

File trac_13961-move_stuff_around.patch, 17.5 KB (added by ncohen, 8 years ago)
  • sage/graphs/generic_graph.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1358334072 -3600
    # Node ID 607ad0a92935883746c9197d57919dd251848ac1
    # Parent  ef19ff1169d9f44ce696b467c65421494040b22c
    Compute the root graph of a graph -- move Graph.is_line_graph and GenericGraph.line_graph to sage.graphs.line_graph
    
    diff --git a/sage/graphs/generic_graph.py b/sage/graphs/generic_graph.py
    a b  
    1290212902    def complement(self):
    1290312903        """
    1290412904        Returns the complement of the (di)graph.
    12905        
     12905
    1290612906        The complement of a graph has the same vertices, but exactly those
    1290712907        edges that are not in the original graph. This is not well defined
    1290812908        for graphs with multiple edges.
    12909        
    12910         EXAMPLES::
    12911        
     12909
     12910        EXAMPLES::
     12911
    1291212912            sage: P = graphs.PetersenGraph()
    1291312913            sage: P.plot() # long time
    1291412914            sage: PC = P.complement()
    1291512915            sage: PC.plot() # long time
    12916        
    12917         ::
    12918        
     12916
     12917        ::
     12918
    1291912919            sage: graphs.TetrahedralGraph().complement().size()
    1292012920            0
    1292112921            sage: graphs.CycleGraph(4).complement().edges()
     
    1294112941                    G.add_edge(u,v)
    1294212942        return G
    1294312943
    12944     def line_graph(self, labels=True):
    12945         """
    12946         Returns the line graph of the (di)graph.
    12947 
    12948         INPUT:
    12949 
    12950         - ``labels`` (boolean) -- whether edge labels should be taken in
    12951           consideration. If ``labels=True``, the vertices of the line graph will
    12952           be triples ``(u,v,label)``, and pairs of vertices otherwise.
    12953 
    12954           This is set to ``True`` by default.
    12955 
    12956         The line graph of an undirected graph G is an undirected graph H
    12957         such that the vertices of H are the edges of G and two vertices e
    12958         and f of H are adjacent if e and f share a common vertex in G. In
    12959         other words, an edge in H represents a path of length 2 in G.
    12960 
    12961         The line graph of a directed graph G is a directed graph H such
    12962         that the vertices of H are the edges of G and two vertices e and f
    12963         of H are adjacent if e and f share a common vertex in G and the
    12964         terminal vertex of e is the initial vertex of f. In other words, an
    12965         edge in H represents a (directed) path of length 2 in G.
    12966 
    12967         .. NOTE::
    12968 
    12969             As a :class:`Graph` object only accepts hashable objects as vertices
    12970             (and as the vertices of the line graph are the edges of the graph),
    12971             this code will fail if edge labels are not hashable. You can also
    12972             set the argument ``labels=False`` to ignore labels.
    12973 
    12974         EXAMPLES::
    12975 
    12976             sage: g = graphs.CompleteGraph(4)
    12977             sage: h = g.line_graph()
    12978             sage: h.vertices()
    12979             [(0, 1, None),
    12980             (0, 2, None),
    12981             (0, 3, None),
    12982             (1, 2, None),
    12983             (1, 3, None),
    12984             (2, 3, None)]
    12985             sage: h.am()
    12986             [0 1 1 1 1 0]
    12987             [1 0 1 1 0 1]
    12988             [1 1 0 0 1 1]
    12989             [1 1 0 0 1 1]
    12990             [1 0 1 1 0 1]
    12991             [0 1 1 1 1 0]
    12992             sage: h2 = g.line_graph(labels=False)
    12993             sage: h2.vertices()
    12994             [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
    12995             sage: h2.am() == h.am()
    12996             True
    12997             sage: g = DiGraph([[1..4],lambda i,j: i<j])
    12998             sage: h = g.line_graph()
    12999             sage: h.vertices()
    13000             [(1, 2, None),
    13001             (1, 3, None),
    13002             (1, 4, None),
    13003             (2, 3, None),
    13004             (2, 4, None),
    13005             (3, 4, None)]
    13006             sage: h.edges()
    13007             [((1, 2, None), (2, 3, None), None),
    13008              ((1, 2, None), (2, 4, None), None),
    13009              ((1, 3, None), (3, 4, None), None),
    13010              ((2, 3, None), (3, 4, None), None)]
    13011 
    13012         Tests:
    13013 
    13014         :trac:`13787`::
    13015 
    13016             sage: g = graphs.KneserGraph(7,1)
    13017             sage: C = graphs.CompleteGraph(7)
    13018             sage: C.is_isomorphic(g)
    13019             True
    13020             sage: C.line_graph().is_isomorphic(g.line_graph())
    13021             True
    13022         """
    13023         if self._directed:
    13024             from sage.graphs.digraph import DiGraph
    13025             G=DiGraph()
    13026             G.add_vertices(self.edges(labels=labels))
    13027             for v in self:
    13028                 # Connect appropriate incident edges of the vertex v
    13029                 G.add_edges([(e,f) for e in self.incoming_edge_iterator(v, labels=labels) \
    13030                              for f in self.outgoing_edge_iterator(v, labels=labels)])
    13031             return G
    13032         else:
    13033             from sage.graphs.all import Graph
    13034             G=Graph()
    13035 
    13036             # We must sort the edges' endpoints so that (1,2,None) is seen as
    13037             # the same edge as (2,1,None).
    13038             #
    13039             # We do so by comparing hashes, just in case all the natural order
    13040             # (<) on vertices would not be a total order (for instance when
    13041             # vertices are sets). If two adjacent vertices have the same hash,
    13042             # then we store the pair in the dictionary of conflicts
    13043 
    13044             conflicts = {}
    13045 
    13046             # 1) List of vertices in the line graph
    13047             elist = []
    13048             for e in self.edge_iterator(labels = labels):
    13049                 if hash(e[0]) < hash(e[1]):
    13050                     elist.append(e)
    13051                 elif hash(e[0]) > hash(e[1]):
    13052                     elist.append((e[1],e[0])+e[2:])
    13053                 else:
    13054                     # Settle the conflict arbitrarily
    13055                     conflicts[e] = e
    13056                     conflicts[(e[1],e[0])+e[2:]] = e
    13057                     elist.append(e)
    13058 
    13059             G.add_vertices(elist)
    13060 
    13061             # 2) adjacencies in the line graph
    13062             for v in self:
    13063                 elist = []
    13064 
    13065                 # Add the edge to the list, according to hashes, as previously
    13066                 for e in self.edge_iterator(v, labels=labels):
    13067                     if hash(e[0]) < hash(e[1]):
    13068                         elist.append(e)
    13069                     elif hash(e[0]) > hash(e[1]):
    13070                         elist.append((e[1],e[0])+e[2:])
    13071                     else:
    13072                         elist.append(conflicts[e])
    13073 
    13074                 # Alls pairs of elements in elist are edges of the
    13075                 # line graph
    13076                 while elist:
    13077                     x = elist.pop()
    13078                     for y in elist:
    13079                         G.add_edge(x,y)
    13080 
    13081             return G
    13082 
    1308312944    def to_simple(self):
    1308412945        """
    1308512946        Returns a simple version of itself (i.e., undirected and loops and
     
    1310912970    def disjoint_union(self, other, verbose_relabel=True):
    1311012971        """
    1311112972        Returns the disjoint union of self and other.
    13112        
     12973
    1311312974        If the graphs have common vertices, the vertices will be renamed to
    1311412975        form disjoint sets.
    13115        
    13116         INPUT:
    13117        
    13118        
     12976
     12977        INPUT:
     12978
    1311912979        -  ``verbose_relabel`` - (defaults to True) If True
    1312012980           and the graphs have common vertices, then each vertex v in the
    1312112981           first graph will be changed to '0,v' and each vertex u in the
    1312212982           second graph will be changed to '1,u'. If False, the vertices of
    1312312983           the first graph and the second graph will be relabeled with
    1312412984           consecutive integers.
    13125        
    13126        
    13127         EXAMPLES::
    13128        
     12985
     12986        EXAMPLES::
     12987
    1312912988            sage: G = graphs.CycleGraph(3)
    1313012989            sage: H = graphs.CycleGraph(4)
    1313112990            sage: J = G.disjoint_union(H); J
     
    1685516714GenericGraph.distances_distribution = types.MethodType(sage.graphs.distances_all_pairs.distances_distribution, None, GenericGraph)
    1685616715GenericGraph.wiener_index = types.MethodType(sage.graphs.distances_all_pairs.wiener_index, None, GenericGraph)
    1685716716
     16717# From Python modules
     16718import sage.graphs.line_graph
     16719GenericGraph.line_graph = sage.graphs.line_graph.line_graph
     16720
    1685816721def tachyon_vertex_plot(g, bgcolor=(1,1,1),
    1685916722                        vertex_colors=None,
    1686016723                        vertex_size=0.06,
  • sage/graphs/graph.py

    diff --git a/sage/graphs/graph.py b/sage/graphs/graph.py
    a b  
    18391839
    18401840        return True
    18411841
    1842     def is_line_graph(self, certificate = False):
    1843         r"""
    1844         Tests wether the graph is a line graph.
    1845 
    1846         INPUT:
    1847 
    1848         - ``certificate`` (boolean) -- whether to return a certificate
    1849           when the graph is *not* a line graph. When ``certificate``
    1850           is set to ``True``, and if the graph is not a line graph,
    1851           the method returns a subgraph isomorphic to one of the 9
    1852           forbidden induced subgraphs of a line graph (instead of the
    1853           usual ``False``)
    1854 
    1855         .. TODO::
    1856 
    1857             This methods sequentially tests each of the forbidden subgraphs,
    1858             which is a very slow method. There exist much better algorithms,
    1859             including those which are actually able to return a graph whose line
    1860             graph is isomorphic to the given graph.
    1861 
    1862         EXAMPLES:
    1863 
    1864         A complete graph is always the line graph of a star::
    1865 
    1866             sage: graphs.CompleteGraph(5).is_line_graph()
    1867             True
    1868 
    1869         The Petersen Graph not being claw-free, it is not a line
    1870         graph:
    1871 
    1872             sage: graphs.PetersenGraph().is_line_graph()
    1873             False
    1874 
    1875         This is indeed the subgraph returned::
    1876 
    1877             sage: C = graphs.PetersenGraph().is_line_graph(certificate = True)
    1878             sage: C.is_isomorphic(graphs.ClawGraph())
    1879             True
    1880         """
    1881         from sage.graphs.graph_generators import graphs
    1882 
    1883         for g in graphs.line_graph_forbidden_subgraphs():
    1884             h = self.subgraph_search(g, induced = True)
    1885             if h is not None:
    1886                 if certificate:
    1887                     return h
    1888                 else:
    1889                     return False
    1890 
    1891         return True
    1892 
    18931842    def is_bipartite(self, certificate = False):
    18941843        """
    18951844        Returns ``True`` if graph `G` is bipartite, ``False`` if not.
     
    19671916            return True, color
    19681917        else:
    19691918            return True
    1970        
     1919
    19711920    def is_triangle_free(self, algorithm='bitset'):
    19721921        r"""
    19731922        Returns whether ``self`` is triangle-free
     
    58405789import sage.graphs.graph_decompositions.graph_products
    58415790Graph.is_cartesian_product = types.MethodType(sage.graphs.graph_decompositions.graph_products.is_cartesian_product, None, Graph)
    58425791
     5792# From Python modules
     5793import sage.graphs.line_graph
     5794Graph.is_line_graph = sage.graphs.line_graph.is_line_graph
     5795
    58435796def compare_edges(x, y):
    58445797    """
    58455798    This function has been deprecated.
  • sage/graphs/line_graph.py

    diff --git a/sage/graphs/line_graph.py b/sage/graphs/line_graph.py
    a b  
    1515
    1616Author:
    1717
    18 - Nathann Cohen (01-2013), while listening to Nina Simone *"I wish I
    19   knew how it would feel to be free"*. Crazy good song. And *"Prendre
    20   ta douleur"*, too.
     18- Nathann Cohen (01-2013), :meth:`root_graph` method and module documentation.
     19  Written while listening to Nina Simone *"I wish I knew how it would feel to be
     20  free"*. Crazy good song. And *"Prendre ta douleur"*, too.
    2121
    2222Definition
    2323-----------
     
    149149---------
    150150"""
    151151
     152def is_line_graph(g, certificate = False):
     153    r"""
     154    Tests wether the graph is a line graph.
     155
     156    INPUT:
     157
     158    - ``certificate`` (boolean) -- whether to return a certificate when the
     159      graph is *not* a line graph. When ``certificate`` is set to ``True``, and
     160      if the graph is not a line graph, the method returns a subgraph isomorphic
     161      to one of the 9 forbidden induced subgraphs of a line graph (instead of
     162      the usual ``False``)
     163
     164    .. TODO::
     165
     166        This methods sequentially tests each of the forbidden subgraphs, which
     167        is a very slow method. There exist much better algorithms, including
     168        those which are actually able to return a graph whose line graph is
     169        isomorphic to the given graph.
     170
     171    EXAMPLES:
     172
     173    A complete graph is always the line graph of a star::
     174
     175        sage: graphs.CompleteGraph(5).is_line_graph()
     176        True
     177
     178    The Petersen Graph not being claw-free, it is not a line
     179    graph:
     180
     181        sage: graphs.PetersenGraph().is_line_graph()
     182        False
     183
     184    This is indeed the subgraph returned::
     185
     186        sage: C = graphs.PetersenGraph().is_line_graph(certificate = True)
     187        sage: C.is_isomorphic(graphs.ClawGraph())
     188        True
     189    """
     190    from sage.graphs.graph_generators import graphs
     191
     192    for fg in graphs.line_graph_forbidden_subgraphs():
     193        h = g.subgraph_search(fg, induced = True)
     194        if h is not None:
     195            if certificate:
     196                return h
     197            else:
     198                return False
     199
     200    return True
     201
     202def line_graph(self, labels=True):
     203    """
     204    Returns the line graph of the (di)graph.
     205
     206    INPUT:
     207
     208    - ``labels`` (boolean) -- whether edge labels should be taken in
     209      consideration. If ``labels=True``, the vertices of the line graph will be
     210      triples ``(u,v,label)``, and pairs of vertices otherwise.
     211
     212      This is set to ``True`` by default.
     213
     214    The line graph of an undirected graph G is an undirected graph H such that
     215    the vertices of H are the edges of G and two vertices e and f of H are
     216    adjacent if e and f share a common vertex in G. In other words, an edge in H
     217    represents a path of length 2 in G.
     218
     219    The line graph of a directed graph G is a directed graph H such that the
     220    vertices of H are the edges of G and two vertices e and f of H are adjacent
     221    if e and f share a common vertex in G and the terminal vertex of e is the
     222    initial vertex of f. In other words, an edge in H represents a (directed)
     223    path of length 2 in G.
     224
     225    .. NOTE::
     226
     227        As a :class:`Graph` object only accepts hashable objects as vertices
     228        (and as the vertices of the line graph are the edges of the graph), this
     229        code will fail if edge labels are not hashable. You can also set the
     230        argument ``labels=False`` to ignore labels.
     231
     232    EXAMPLES::
     233
     234        sage: g = graphs.CompleteGraph(4)
     235        sage: h = g.line_graph()
     236        sage: h.vertices()
     237        [(0, 1, None),
     238        (0, 2, None),
     239        (0, 3, None),
     240        (1, 2, None),
     241        (1, 3, None),
     242        (2, 3, None)]
     243        sage: h.am()
     244        [0 1 1 1 1 0]
     245        [1 0 1 1 0 1]
     246        [1 1 0 0 1 1]
     247        [1 1 0 0 1 1]
     248        [1 0 1 1 0 1]
     249        [0 1 1 1 1 0]
     250        sage: h2 = g.line_graph(labels=False)
     251        sage: h2.vertices()
     252        [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
     253        sage: h2.am() == h.am()
     254        True
     255        sage: g = DiGraph([[1..4],lambda i,j: i<j])
     256        sage: h = g.line_graph()
     257        sage: h.vertices()
     258        [(1, 2, None),
     259        (1, 3, None),
     260        (1, 4, None),
     261        (2, 3, None),
     262        (2, 4, None),
     263        (3, 4, None)]
     264        sage: h.edges()
     265        [((1, 2, None), (2, 3, None), None),
     266         ((1, 2, None), (2, 4, None), None),
     267         ((1, 3, None), (3, 4, None), None),
     268         ((2, 3, None), (3, 4, None), None)]
     269
     270    Tests:
     271
     272    :trac:`13787`::
     273
     274        sage: g = graphs.KneserGraph(7,1)
     275        sage: C = graphs.CompleteGraph(7)
     276        sage: C.is_isomorphic(g)
     277        True
     278        sage: C.line_graph().is_isomorphic(g.line_graph())
     279        True
     280    """
     281    if self._directed:
     282        from sage.graphs.digraph import DiGraph
     283        G=DiGraph()
     284        G.add_vertices(self.edges(labels=labels))
     285        for v in self:
     286            # Connect appropriate incident edges of the vertex v
     287            G.add_edges([(e,f) for e in self.incoming_edge_iterator(v, labels=labels) \
     288                         for f in self.outgoing_edge_iterator(v, labels=labels)])
     289        return G
     290    else:
     291        from sage.graphs.all import Graph
     292        G=Graph()
     293
     294        # We must sort the edges' endpoints so that (1,2,None) is seen as
     295        # the same edge as (2,1,None).
     296        #
     297        # We do so by comparing hashes, just in case all the natural order
     298        # (<) on vertices would not be a total order (for instance when
     299        # vertices are sets). If two adjacent vertices have the same hash,
     300        # then we store the pair in the dictionary of conflicts
     301
     302        conflicts = {}
     303
     304        # 1) List of vertices in the line graph
     305        elist = []
     306        for e in self.edge_iterator(labels = labels):
     307            if hash(e[0]) < hash(e[1]):
     308                elist.append(e)
     309            elif hash(e[0]) > hash(e[1]):
     310                elist.append((e[1],e[0])+e[2:])
     311            else:
     312                # Settle the conflict arbitrarily
     313                conflicts[e] = e
     314                conflicts[(e[1],e[0])+e[2:]] = e
     315                elist.append(e)
     316
     317        G.add_vertices(elist)
     318
     319        # 2) adjacencies in the line graph
     320        for v in self:
     321            elist = []
     322
     323            # Add the edge to the list, according to hashes, as previously
     324            for e in self.edge_iterator(v, labels=labels):
     325                if hash(e[0]) < hash(e[1]):
     326                    elist.append(e)
     327                elif hash(e[0]) > hash(e[1]):
     328                    elist.append((e[1],e[0])+e[2:])
     329                else:
     330                    elist.append(conflicts[e])
     331
     332            # Alls pairs of elements in elist are edges of the
     333            # line graph
     334            while elist:
     335                x = elist.pop()
     336                for y in elist:
     337                    G.add_edge(x,y)
     338
     339        return G
     340
    152341def root_graph(g, verbose = False):
    153342    r"""
    154343    Computes the root graph corresponding to the given graph