Ticket #7724: trac_7724_iterator-rebased.patch

File trac_7724_iterator-rebased.patch, 12.5 KB (added by rlm, 11 years ago)
  • sage/graphs/base/c_graph.pyx

    # HG changeset patch
    # User Yann Laigle-Chapuy <yannlaiglechapuy@gmail.com>
    # Date 1261410197 -3600
    # Node ID b66143e70dba9437c95d1f33dbfa26959097db54
    # Parent  2a0d2c20d545899643823ba6cb346ac9774125c0
    #7724 depth_first_search iterator
    
    diff -r 2a0d2c20d545 -r b66143e70dba sage/graphs/base/c_graph.pyx
    a b  
    13891389
    13901390            return shortest_path
    13911391           
     1392    def depth_first_search(self, v, reverse=False, ignore_direction=False):
     1393        r"""
     1394        Returns a depth-first search from vertex v.
     1395 
     1396        INPUT:
     1397 
     1398        - ``reverse`` -- considers the reversed graph (
     1399          the out_neighbors become in_neighbors ).
     1400 
     1401          The default value is ``False``.
     1402
     1403        - ``ignore_direction`` -- consider the undirected graph.
     1404
     1405          The default value is ``False``.
     1406
     1407        EXAMPLE::
     1408                                                                                                 
     1409            sage: G = Graph(graphs.PetersenGraph(), implementation='c_graph')
     1410            sage: list(G.depth_first_search(0))
     1411            [0, 5, 8, 6, 9, 7, 2, 3, 4, 1]
     1412        """
     1413        return Search_iterator(self, v, direction=-1, reverse=reverse, ignore_direction=ignore_direction)
     1414
     1415    def breadth_first_search(self, v, reverse=False, ignore_direction=False):
     1416        r"""
     1417        Returns a breadth-first search from vertex v.
     1418
     1419        INPUT:
     1420
     1421        - ``reverse`` -- considers the reversed graph (
     1422          the out_neighbors become in_neighbors ).
     1423
     1424          The default value is ``False``.
     1425
     1426        - ``ignore_direction`` -- consider the undirected graph.
     1427
     1428          The default value is ``False``.
     1429
     1430
     1431        EXAMPLE::
     1432                                                                                                 
     1433            sage: G = Graph(graphs.PetersenGraph(), implementation='c_graph')
     1434            sage: list(G.breadth_first_search(0))
     1435            [0, 1, 4, 5, 2, 6, 3, 9, 7, 8]
     1436        """
     1437        return Search_iterator(self, v, direction=0, reverse=reverse, ignore_direction=ignore_direction)
     1438
     1439    def is_connected(self):
     1440        r"""
     1441        Returns whether the graph is connected.
     1442
     1443        EXAMPLE:
     1444
     1445        Petersen's graph is connected ::
     1446
     1447           sage: DiGraph(graphs.PetersenGraph(),implementation="c_graph").is_connected()
     1448           True
     1449
     1450        While the disjoint union of two of them is not::
     1451
     1452           sage: DiGraph(2*graphs.PetersenGraph(),implementation="c_graph").is_connected()
     1453           False
     1454        """
     1455
     1456        cdef int v_int = 0
     1457        v_int = bitset_first((<CGraph>self._cg).active_vertices)
     1458
     1459        if v_int == -1:
     1460            return True
     1461
     1462        return len(list(self.depth_first_search(get_vertex(v_int, self.vertex_ints, self.vertex_labels, self._cg),\
     1463                        ignore_direction=True))\
     1464                       ) == (<CGraph>self._cg).num_verts
     1465
     1466    def is_strongly_connected(self):
     1467        r"""
     1468        Returns whether the graph is strongly connected.
     1469
     1470        EXAMPLE:
     1471       
     1472        The circuit on 3 vertices is obviously strongly connected ::
     1473
     1474            sage: g = DiGraph({ 0 : [1], 1 : [2], 2 : [0]},implementation="c_graph")
     1475            sage: g.is_strongly_connected()
     1476            True
     1477
     1478        But a transitive triangle is not::
     1479
     1480            sage: g = DiGraph({ 0 : [1,2], 1 : [2]},implementation="c_graph")
     1481            sage: g.is_strongly_connected()
     1482            False
     1483        """
     1484        cdef int v_int = 0
     1485
     1486        # Pick one vertex
     1487        v_int = bitset_first((<CGraph>self._cg).active_vertices)
     1488
     1489        if v_int == -1:
     1490            return True
     1491
     1492        v = get_vertex(v_int, self.vertex_ints, self.vertex_labels, self._cg)
     1493       
     1494        return (<CGraph>self._cg).num_verts == len(list(self.depth_first_search(v))) and \
     1495            (<CGraph>self._cg).num_verts == len(list(self.depth_first_search(v, reverse=True)))
     1496
     1497
     1498cdef class Search_iterator:
     1499    cdef graph
     1500    cdef int direction
     1501    cdef list stack
     1502    cdef bitset_t seen
     1503    cdef bool test_out
     1504    cdef bool test_in
     1505
     1506    def __init__(self, graph, v, direction=0, reverse=False, ignore_direction=False):
     1507        self.graph = graph
     1508        self.direction = direction
     1509
     1510        bitset_init(self.seen,(<CGraph>self.graph._cg).active_vertices.size)
     1511        bitset_set_first_n(self.seen,0)
     1512
     1513        self.stack = [get_vertex(v, self.graph.vertex_ints, self.graph.vertex_labels, self.graph._cg)]
     1514
     1515        if not self.graph.directed:
     1516            ignore_direction = False
     1517
     1518        self.test_out = (not reverse) or ignore_direction
     1519        self.test_in = reverse or ignore_direction
     1520
     1521    def __iter__(self):
     1522        return self
     1523
     1524    def __next__(self):
     1525        cdef int v_int
     1526        cdef int w_int       
     1527
     1528        while self.stack:
     1529            v_int = self.stack.pop(self.direction)
     1530
     1531            if bitset_not_in(self.seen,v_int):
     1532                value = vertex_label(v_int, self.graph.vertex_ints, self.graph.vertex_labels, self.graph._cg)
     1533                bitset_add(self.seen,v_int)
     1534
     1535                if self.test_out:
     1536                    self.stack.extend(self.graph._cg.out_neighbors(v_int))
     1537                if self.test_in:
     1538                    self.stack.extend(self.graph._cg.in_neighbors(v_int))
     1539
     1540                break
     1541        else:
     1542            bitset_free(self.seen)
     1543            raise StopIteration
     1544
     1545        return value
    13921546       
    13931547   
    13941548           
  • sage/graphs/graph.py

    diff -r 2a0d2c20d545 -r b66143e70dba sage/graphs/graph.py
    a b  
    32003200        """
    32013201        if self.order() == 0:
    32023202            return True
    3203         v = self.vertex_iterator().next()
    3204         conn_verts = list(self.breadth_first_search(v, ignore_direction=True))
    3205         return len(conn_verts) == self.num_verts()
     3203
     3204        try:
     3205            return self._backend.is_connected()
     3206        except AttributeError:
     3207            v = self.vertex_iterator().next()
     3208            conn_verts = list(self.depth_first_search(v, ignore_direction=True))
     3209            return len(conn_verts) == self.num_verts()
    32063210   
    32073211    def connected_components(self):
    32083212        """
     
    32763280            sage: D.connected_component_containing_vertex(0)
    32773281            [0, 1, 2, 3]
    32783282        """
    3279         c = list(self.breadth_first_search(vertex, ignore_direction=True))
     3283        try:
     3284            c = list(self._backend.depth_first_search(vertex, ignore_direction=True))
     3285        except AttributeError:
     3286            c = list(self.depth_first_search(vertex, ignore_direction=True))
     3287
    32803288        c.sort()
    32813289        return c
    32823290
     
    81418149            [0, 1, 2]
    81428150
    81438151        """
    8144         if neighbors is None:
    8145             if not self._directed or ignore_direction:
    8146                 neighbors=self.neighbor_iterator           
    8147             else:
    8148                 neighbors=self.neighbor_out_iterator
    8149         seen=set([])
    8150         if isinstance(start, list):
    8151             queue=[(v,0) for v in start]
    8152         else:
    8153             queue=[(start,0)]
    8154        
    8155         for v,d in queue:
    8156             yield v
    8157             seen.add(v)
    8158 
    8159         while len(queue)>0:
    8160             v,d = queue.pop(0)
    8161             if distance is None or d<distance:
    8162                 for w in neighbors(v):
    8163                     if w not in seen:
    8164                         seen.add(w)
    8165                         queue.append((w, d+1))
    8166                         yield w
     8152        # Preferably use the Cython implementation
     8153        if neighbors is None and not isinstance(start,list) and distance is None and hasattr(self._backend,"breadth_first_search"):
     8154            for v in self._backend.breadth_first_search(start, ignore_direction = ignore_direction):
     8155                yield v
     8156        else:
     8157            if neighbors is None:
     8158                if not self._directed or ignore_direction:
     8159                    neighbors=self.neighbor_iterator           
     8160                else:
     8161                    neighbors=self.neighbor_out_iterator
     8162            seen=set([])
     8163            if isinstance(start, list):
     8164                queue=[(v,0) for v in start]
     8165            else:
     8166                queue=[(start,0)]
     8167           
     8168            for v,d in queue:
     8169                yield v
     8170                seen.add(v)
     8171   
     8172            while len(queue)>0:
     8173                v,d = queue.pop(0)
     8174                if distance is None or d<distance:
     8175                    for w in neighbors(v):
     8176                        if w not in seen:
     8177                            seen.add(w)
     8178                            queue.append((w, d+1))
     8179                            yield w
    81678180
    81688181    def depth_first_search(self, start, ignore_direction=False, distance=None, neighbors=None):
    81698182        """
     
    82518264            [0, 2, 1]
    82528265
    82538266        """
    8254         if neighbors is None:
    8255             if not self._directed or ignore_direction:
    8256                 neighbors=self.neighbor_iterator           
    8257             else:
    8258                 neighbors=self.neighbor_out_iterator
    8259         seen=set([])
    8260         if isinstance(start, list):
    8261             # Reverse the list so that the initial vertices come out in the same order
    8262             queue=[(v,0) for v in reversed(start)]
    8263         else:
    8264             queue=[(start,0)]
    8265        
    8266         while len(queue)>0:
    8267             v,d = queue.pop()
    8268             if v not in seen:
    8269                 yield v
    8270                 seen.add(v)
    8271                 if distance is None or d<distance:
    8272                     for w in neighbors(v):
    8273                         if w not in seen:
    8274                             queue.append((w, d+1))
     8267        # Preferably use the Cython implementation
     8268        if neighbors is None and not isinstance(start,list) and  distance is None and hasattr(self._backend,"depth_first_search"):
     8269            for v in self._backend.depth_first_search(start, ignore_direction = ignore_direction):
     8270                yield v
     8271        else:
     8272            if neighbors is None:
     8273                if not self._directed or ignore_direction:
     8274                    neighbors=self.neighbor_iterator           
     8275                else:
     8276                    neighbors=self.neighbor_out_iterator
     8277            seen=set([])
     8278            if isinstance(start, list):
     8279                # Reverse the list so that the initial vertices come out in the same order
     8280                queue=[(v,0) for v in reversed(start)]
     8281            else:
     8282                queue=[(start,0)]
     8283           
     8284            while len(queue)>0:
     8285                v,d = queue.pop()
     8286                if v not in seen:
     8287                    yield v
     8288                    seen.add(v)
     8289                    if distance is None or d<distance:
     8290                        for w in neighbors(v):
     8291                            if w not in seen:
     8292                                queue.append((w, d+1))
    82758293
    82768294    def lex_BFS(self,reverse=False,tree=False):
    82778295        r"""
     
    1172411742                self._weighted = weighted
    1172511743                self.allow_loops(loops, check=False)
    1172611744                self.allow_multiple_edges(multiedges, check=False)
     11745            self._backend.directed = False                   
    1172711746        else:
    1172811747            raise NotImplementedError("Supported implementations: networkx, c_graph.")
    1172911748
     
    1399414013                self._weighted = weighted
    1399514014                self.allow_loops(loops, check=False)
    1399614015                self.allow_multiple_edges(multiedges, check=False)
     14016            self._backend.directed = True
    1399714017        else:
    1399814018            raise NotImplementedError("Supported implementations: networkx, c_graph.")
    1399914019
     
    1488614906        import networkx
    1488714907        return networkx.strongly_connected_components(self.networkx_graph(copy=False))
    1488814908
     14909    def is_strongly_connected(self):
     14910        r"""
     14911        Returns whether the current ``DiGraph`` is strongly connected.
     14912
     14913        EXAMPLE:
     14914       
     14915        The circuit is obviously strongly connected ::
     14916
     14917            sage: g = digraphs.Circuit(5)
     14918            sage: g.is_strongly_connected()
     14919            True
     14920
     14921        But a transitive triangle is not::
     14922
     14923            sage: g = DiGraph({ 0 : [1,2], 1 : [2]})
     14924            sage: g.is_strongly_connected()
     14925            False
     14926        """
     14927        if self.order()==1:
     14928            return True
     14929
     14930        try:
     14931            return self._backend.is_strongly_connected()
     14932
     14933        except AttributeError:
     14934            return len(self.strongly_connected_components()) == 1
     14935
     14936
    1488914937def tachyon_vertex_plot(g, bgcolor=(1,1,1),
    1489014938                        vertex_colors=None,
    1489114939                        vertex_size=0.06,